diff --git a/client/homebrew/navbar/recent.navitem.jsx b/client/homebrew/navbar/recent.navitem.jsx
index a6cbbf406..4c4722515 100644
--- a/client/homebrew/navbar/recent.navitem.jsx
+++ b/client/homebrew/navbar/recent.navitem.jsx
@@ -5,8 +5,8 @@ const Moment = require('moment');
const Nav = require('naturalcrit/nav/nav.jsx');
-const EDIT_KEY = 'homebrewery-recently-edited';
-const VIEW_KEY = 'homebrewery-recently-viewed';
+const EDIT_KEY = 'HB_nav_recentlyEdited';
+const VIEW_KEY = 'HB_nav_recentlyViewed';
const RecentItems = createClass({
diff --git a/client/homebrew/pages/accountPage/accountPage.jsx b/client/homebrew/pages/accountPage/accountPage.jsx
index 598683504..b69eb6e3e 100644
--- a/client/homebrew/pages/accountPage/accountPage.jsx
+++ b/client/homebrew/pages/accountPage/accountPage.jsx
@@ -13,7 +13,7 @@ const AccountPage = (props)=>{
// initialize save location from local storage based on user id
React.useEffect(()=>{
if(!saveLocation && accountDetails.username) {
- SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${accountDetails.username}`;
+ SAVEKEY = `HB_editor_defaultSave_${accountDetails.username}`;
// if no SAVEKEY in local storage, default save location to Google Drive if user has Google account.
let saveLocation = window.localStorage.getItem(SAVEKEY);
saveLocation = saveLocation ?? (accountDetails.googleId ? 'GOOGLE-DRIVE' : 'HOMEBREWERY');
diff --git a/client/homebrew/pages/basePages/listPage/listPage.jsx b/client/homebrew/pages/basePages/listPage/listPage.jsx
index ec557ffb1..4afc14364 100644
--- a/client/homebrew/pages/basePages/listPage/listPage.jsx
+++ b/client/homebrew/pages/basePages/listPage/listPage.jsx
@@ -7,7 +7,9 @@ const moment = require('moment');
const BrewItem = require('./brewItem/brewItem.jsx');
-const USERPAGE_KEY_PREFIX = 'HOMEBREWERY-LISTPAGE';
+const USERPAGE_SORT_DIR = 'HB_listPage_sortDir';
+const USERPAGE_SORT_TYPE = 'HB_listPage_sortType';
+const USERPAGE_GROUP_VISIBILITY_PREFIX = 'HB_listPage_visibility_group';
const DEFAULT_SORT_TYPE = 'alpha';
const DEFAULT_SORT_DIR = 'asc';
@@ -50,12 +52,12 @@ const ListPage = createClass({
// LOAD FROM LOCAL STORAGE
if(typeof window !== 'undefined') {
- const newSortType = (this.state.sortType ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`) || DEFAULT_SORT_TYPE));
- const newSortDir = (this.state.sortDir ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`) || DEFAULT_SORT_DIR));
+ const newSortType = (this.state.sortType ?? (localStorage.getItem(USERPAGE_SORT_TYPE) || DEFAULT_SORT_TYPE));
+ const newSortDir = (this.state.sortDir ?? (localStorage.getItem(USERPAGE_SORT_DIR) || DEFAULT_SORT_DIR));
this.updateUrl(this.state.filterString, newSortType, newSortDir);
const brewCollection = this.props.brewCollection.map((brewGroup)=>{
- brewGroup.visible = (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`) ?? 'true')=='true';
+ brewGroup.visible = (localStorage.getItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`) ?? 'true')=='true';
return brewGroup;
});
@@ -73,10 +75,10 @@ const ListPage = createClass({
saveToLocalStorage : function() {
this.state.brewCollection.map((brewGroup)=>{
- localStorage.setItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`, `${brewGroup.visible}`);
+ localStorage.setItem(`${USERPAGE_GROUP_VISIBILITY_PREFIX}_${brewGroup.class}`, `${brewGroup.visible}`);
});
- localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`, this.state.sortType);
- localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`, this.state.sortDir);
+ localStorage.setItem(USERPAGE_SORT_TYPE, this.state.sortType);
+ localStorage.setItem(USERPAGE_SORT_DIR, this.state.sortDir);
},
renderBrews : function(brews){
diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx
index 6c2220ec1..e3d449a55 100644
--- a/client/homebrew/pages/editPage/editPage.jsx
+++ b/client/homebrew/pages/editPage/editPage.jsx
@@ -1,44 +1,54 @@
/* eslint-disable max-lines */
import './editPage.less';
-import React, { useState, useEffect, useRef, useCallback } from 'react';
+// Common imports
+import React, { useState, useEffect, useRef } from 'react';
import request from '../../utils/request-middleware.js';
import Markdown from 'naturalcrit/markdown.js';
-import _ from 'lodash';;
-import { makePatches, stringifyPatches } from '@sanity/diff-match-patch';
-import { md5 } from 'hash-wasm';
-import { gzipSync, strToU8 } from 'fflate';
-import { Meta } from 'vitreum/headtags';
+import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
+import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js';
+
+import SplitPane from 'client/components/splitPane/splitPane.jsx';
+import Editor from '../../editor/editor.jsx';
+import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
import Nav from 'naturalcrit/nav/nav.jsx';
import Navbar from '../../navbar/navbar.jsx';
import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
import AccountNavItem from '../../navbar/account.navitem.jsx';
-import ShareNavItem from '../../navbar/share.navitem.jsx';
import ErrorNavItem from '../../navbar/error-navitem.jsx';
import HelpNavItem from '../../navbar/help.navitem.jsx';
import VaultNavItem from '../../navbar/vault.navitem.jsx';
import PrintNavItem from '../../navbar/print.navitem.jsx';
import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
-import SplitPane from 'client/components/splitPane/splitPane.jsx';
-import Editor from '../../editor/editor.jsx';
-import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
+// Page specific imports
+import { Meta } from 'vitreum/headtags';
+import _ from 'lodash';
+import { md5 } from 'hash-wasm';
+import { gzipSync, strToU8 } from 'fflate';
+import { makePatches, stringifyPatches } from '@sanity/diff-match-patch';
+import ShareNavItem from '../../navbar/share.navitem.jsx';
import LockNotification from './lockNotification/lockNotification.jsx';
-
-import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
-import { printCurrentBrew, fetchThemeBundle } from '../../../../shared/helpers.js';
-
import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js';
-
import googleDriveIcon from '../../googleDrive.svg';
const SAVE_TIMEOUT = 10000;
const UNSAVED_WARNING_TIMEOUT = 900000; //Warn user afer 15 minutes of unsaved changes
const UNSAVED_WARNING_POPUP_TIMEOUT = 4000; //Show the warning for 4 seconds
+
+const AUTOSAVE_KEY = 'HB_editor_autoSaveOn';
+const BREWKEY = 'HB_newPage_content';
+const STYLEKEY = 'HB_newPage_style';
+const SNIPKEY = 'HB_newPage_snippets';
+const METAKEY = 'HB_newPage_meta';
+
+
+const useLocalStorage = false;
+
const EditPage = (props)=>{
props = {
brew : DEFAULT_BREW_LOAD,
@@ -70,7 +80,7 @@ const EditPage = (props)=>{
const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges
useEffect(()=>{
- const autoSavePref = JSON.parse(localStorage.getItem('AUTOSAVE_ON') ?? true);
+ const autoSavePref = JSON.parse(localStorage.getItem(AUTOSAVE_KEY) ?? true);
setAutoSaveEnabled(autoSavePref);
setWarnUnsavedChanges(!autoSavePref);
setHTMLErrors(Markdown.validate(currentBrew.text));
@@ -113,41 +123,27 @@ const EditPage = (props)=>{
editorRef.current?.update();
};
- const handleEditorViewPageChange = (pageNumber)=>{
- setCurrentEditorViewPageNum(pageNumber);
- };
+ const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
+ if (subfield == 'renderer' || subfield == 'theme')
+ fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
- const handleEditorCursorPageChange = (pageNumber)=>{
- setCurrentEditorCursorPageNum(pageNumber);
- };
-
- const handleBrewRendererPageChange = (pageNumber)=>{
- setCurrentBrewRendererPageNum(pageNumber);
- };
-
- const handleTextChange = (text)=>{
//If there are HTML errors, run the validator on every change to give quick feedback
- if(HTMLErrors.length)
- setHTMLErrors(Markdown.validate(text));
- setCurrentBrew((prevBrew)=>({ ...prevBrew, text }));
- };
+ if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
+ setHTMLErrors(Markdown.validate(value));
- const handleStyleChange = (style)=>{
- setCurrentBrew((prevBrew)=>({ ...prevBrew, style }));
- };
+ if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
+ else setCurrentBrew(prev => ({ ...prev, [field]: value }));
- const handleSnipChange = (snippet)=>{
- //If there are HTML errors, run the validator on every change to give quick feedback
- if(HTMLErrors.length)
- setHTMLErrors(Markdown.validate(snippet));
- setCurrentBrew((prevBrew)=>({ ...prevBrew, snippets: snippet }));
- };
-
- const handleMetaChange = (metadata, field = undefined)=>{
- if(field === 'theme' || field === 'renderer')
- fetchThemeBundle(setError, setThemeBundle, metadata.renderer, metadata.theme);
-
- setCurrentBrew((prev)=>({ ...prev, ...metadata }));
+ if(useLocalStorage) {
+ if(field == 'text') localStorage.setItem(BREWKEY, value);
+ if(field == 'style') localStorage.setItem(STYLEKEY, value);
+ if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
+ if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
+ renderer : value.renderer,
+ theme : value.theme,
+ lang : value.lang
+ }));
+ }
};
const updateBrew = (newData)=>setCurrentBrew((prevBrew)=>({
@@ -326,7 +322,7 @@ const EditPage = (props)=>{
const toggleAutoSave = ()=>{
clearTimeout(warnUnsavedTimeout.current);
clearTimeout(saveTimeout.current);
- localStorage.setItem('AUTOSAVE_ON', JSON.stringify(!autoSaveEnabled));
+ localStorage.setItem(AUTOSAVE_KEY, JSON.stringify(!autoSaveEnabled));
setAutoSaveEnabled(!autoSaveEnabled);
setWarnUnsavedChanges(autoSaveEnabled);
};
@@ -356,11 +352,11 @@ const EditPage = (props)=>{
{renderSaveButton()}
{renderAutoSaveButton()}
}
-
-
-
+
+
+
@@ -380,17 +376,14 @@ const EditPage = (props)=>{
{
themeBundle={themeBundle}
errors={HTMLErrors}
lang={currentBrew.lang}
- onPageChange={handleBrewRendererPageChange}
+ onPageChange={setCurrentBrewRendererPageNum}
currentEditorViewPageNum={currentEditorViewPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
currentBrewRendererPageNum={currentBrewRendererPageNum}
diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx
index 84967b1ff..fdc439ab5 100644
--- a/client/homebrew/pages/homePage/homePage.jsx
+++ b/client/homebrew/pages/homePage/homePage.jsx
@@ -1,25 +1,37 @@
+/* eslint-disable max-lines */
import './homePage.less';
-import React from 'react';
-import { useEffect, useState, useRef } from 'react';
-import request from '../../utils/request-middleware.js';
-import { Meta } from 'vitreum/headtags';
+// Common imports
+import React, { useState, useEffect, useRef } from 'react';
+import request from '../../utils/request-middleware.js';
+import Markdown from 'naturalcrit/markdown.js';
-import Nav from 'naturalcrit/nav/nav.jsx';
-import Navbar from '../../navbar/navbar.jsx';
-import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
-import HelpNavItem from '../../navbar/help.navitem.jsx';
-import VaultNavItem from '../../navbar/vault.navitem.jsx';
-import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
-import AccountNavItem from '../../navbar/account.navitem.jsx';
-import ErrorNavItem from '../../navbar/error-navitem.jsx';
-import { fetchThemeBundle } from '../../../../shared/helpers.js';
+import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
+import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js';
-import SplitPane from 'client/components/splitPane/splitPane.jsx';
-import Editor from '../../editor/editor.jsx';
-import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
+import SplitPane from 'client/components/splitPane/splitPane.jsx';
+import Editor from '../../editor/editor.jsx';
+import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
-import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
+import Nav from 'naturalcrit/nav/nav.jsx';
+import Navbar from '../../navbar/navbar.jsx';
+import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
+import AccountNavItem from '../../navbar/account.navitem.jsx';
+import ErrorNavItem from '../../navbar/error-navitem.jsx';
+import HelpNavItem from '../../navbar/help.navitem.jsx';
+import VaultNavItem from '../../navbar/vault.navitem.jsx';
+import PrintNavItem from '../../navbar/print.navitem.jsx';
+import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
+
+// Page specific imports
+import { Meta } from 'vitreum/headtags';
+
+const BREWKEY = 'homebrewery-new';
+const STYLEKEY = 'homebrewery-new-style';
+const SNIPKEY = 'homebrewery-new-snippets';
+const METAKEY = 'homebrewery-new-meta';
+
+const useLocalStorage = false;
const HomePage =(props)=>{
props = {
@@ -28,9 +40,10 @@ const HomePage =(props)=>{
...props
};
- const [brew , setBrew] = useState(props.brew);
+ const [currentBrew , setCurrentBrew] = useState(props.brew);
const [welcomeText , setWelcomeText] = useState(props.brew.text);
const [error , setError] = useState(undefined);
+ const [HTMLErrors , setHTMLErrors] = useState(Markdown.validate(props.brew.text));
const [currentEditorViewPageNum , setCurrentEditorViewPageNum] = useState(1);
const [currentEditorCursorPageNum, setCurrentEditorCursorPageNum] = useState(1);
const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1);
@@ -40,12 +53,28 @@ const HomePage =(props)=>{
const editorRef = useRef(null);
useEffect(()=>{
- fetchThemeBundle(setError, setThemeBundle, brew.renderer, brew.theme);
+ fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme);
+
+ const handleControlKeys = (e)=>{
+ if(!(e.ctrlKey || e.metaKey)) return;
+ if(e.keyCode === 83) trySaveRef.current(true);
+ if(e.keyCode === 80) printCurrentBrew();
+ if([83, 80].includes(e.keyCode)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ };
+
+ document.addEventListener('keydown', handleControlKeys);
+
+ return () => {
+ document.removeEventListener('keydown', handleControlKeys);
+ };
}, []);
const save = ()=>{
request.post('/api')
- .send(brew)
+ .send(currentBrew)
.end((err, res)=>{
if(err) {
setError(err);
@@ -60,20 +89,27 @@ const HomePage =(props)=>{
editorRef.current.update();
};
- const handleEditorViewPageChange = (pageNumber)=>{
- setCurrentEditorViewPageNum(pageNumber);
- };
-
- const handleEditorCursorPageChange = (pageNumber)=>{
- setCurrentEditorCursorPageNum(pageNumber);
- };
-
- const handleBrewRendererPageChange = (pageNumber)=>{
- setCurrentBrewRendererPageNum(pageNumber);
- };
+ const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
+ if (subfield == 'renderer' || subfield == 'theme')
+ fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
- const handleTextChange = (text)=>{
- setBrew((prevBrew) => ({ ...prevBrew, text }));
+ //If there are HTML errors, run the validator on every change to give quick feedback
+ if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
+ setHTMLErrors(Markdown.validate(value));
+
+ if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
+ else setCurrentBrew(prev => ({ ...prev, [field]: value }));
+
+ if(useLocalStorage) {
+ if(field == 'text') localStorage.setItem(BREWKEY, value);
+ if(field == 'style') localStorage.setItem(STYLEKEY, value);
+ if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
+ if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
+ renderer : value.renderer,
+ theme : value.theme,
+ lang : value.lang
+ }));
+ }
};
const clearError = ()=>{
@@ -89,6 +125,7 @@ const HomePage =(props)=>{
null
}
+
@@ -105,22 +142,22 @@ const HomePage =(props)=>{
{
/>
-
+
Save current
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx
index bb21441cf..d1d1fa75c 100644
--- a/client/homebrew/pages/newPage/newPage.jsx
+++ b/client/homebrew/pages/newPage/newPage.jsx
@@ -1,29 +1,40 @@
-/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
+/* eslint-disable max-lines */
import './newPage.less';
+// Common imports
import React, { useState, useEffect, useRef } from 'react';
import request from '../../utils/request-middleware.js';
import Markdown from 'naturalcrit/markdown.js';
-import Nav from 'naturalcrit/nav/nav.jsx';
-import Navbar from '../../navbar/navbar.jsx';
-import AccountNavItem from '../../navbar/account.navitem.jsx';
-import ErrorNavItem from '../../navbar/error-navitem.jsx';
-import HelpNavItem from '../../navbar/help.navitem.jsx';
-import PrintNavItem from '../../navbar/print.navitem.jsx';
-import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
+import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
+import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js';
import SplitPane from 'client/components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
-import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
-import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '../../../../shared/helpers.js';
+import Nav from 'naturalcrit/nav/nav.jsx';
+import Navbar from '../../navbar/navbar.jsx';
+import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
+import AccountNavItem from '../../navbar/account.navitem.jsx';
+import ErrorNavItem from '../../navbar/error-navitem.jsx';
+import HelpNavItem from '../../navbar/help.navitem.jsx';
+import VaultNavItem from '../../navbar/vault.navitem.jsx';
+import PrintNavItem from '../../navbar/print.navitem.jsx';
+import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
-const BREWKEY = 'homebrewery-new';
-const STYLEKEY = 'homebrewery-new-style';
-const METAKEY = 'homebrewery-new-meta';
-const SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${global.account?.username || ''}`;
+// Page specific imports
+import { Meta } from 'vitreum/headtags';
+
+
+const BREWKEY = 'HB_newPage_content';
+const STYLEKEY = 'HB_newPage_style';
+const METAKEY = 'HB_newPage_metadata';
+const SNIPKEY = 'HB_newPage_snippets';
+const SAVEKEYPREFIX = 'HB_editor_defaultSave_';
+
+
+const useLocalStorage = true;
const NewPage = (props) => {
props = {
@@ -44,10 +55,21 @@ const NewPage = (props) => {
const editorRef = useRef(null);
useEffect(() => {
- document.addEventListener('keydown', handleControlKeys);
loadBrew();
fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme);
+ const handleControlKeys = (e)=>{
+ if(!(e.ctrlKey || e.metaKey)) return;
+ if(e.keyCode === 83) trySaveRef.current(true);
+ if(e.keyCode === 80) printCurrentBrew();
+ if([83, 80].includes(e.keyCode)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ };
+
+ document.addEventListener('keydown', handleControlKeys);
+
return () => {
document.removeEventListener('keydown', handleControlKeys);
};
@@ -67,6 +89,7 @@ const NewPage = (props) => {
brew.lang = metaStorage?.lang ?? brew.lang;
}
+ const SAVEKEY = `${SAVEKEYPREFIX}${global.account?.username}`;
const saveStorage = localStorage.getItem(SAVEKEY) || 'HOMEBREWERY';
setCurrentBrew(brew);
@@ -80,68 +103,31 @@ const NewPage = (props) => {
window.history.replaceState({}, window.location.title, '/new/');
};
- const handleControlKeys = (e) => {
- if (!(e.ctrlKey || e.metaKey)) return;
- const S_KEY = 83;
- const P_KEY = 80;
- if (e.keyCode === S_KEY) save();
- if (e.keyCode === P_KEY) printCurrentBrew();
- if (e.keyCode === S_KEY || e.keyCode === P_KEY) {
- e.preventDefault();
- e.stopPropagation();
- }
- };
-
const handleSplitMove = ()=>{
editorRef.current.update();
};
- const handleEditorViewPageChange = (pageNumber)=>{
- setCurrentEditorViewPageNum(pageNumber);
- };
-
- const handleEditorCursorPageChange = (pageNumber)=>{
- setCurrentEditorCursorPageNum(pageNumber);
- };
-
- const handleBrewRendererPageChange = (pageNumber)=>{
- setCurrentBrewRendererPageNum(pageNumber);
- };
+ const handleBrewChange = (field) => (value, subfield) => { //'text', 'style', 'snippets', 'metadata'
+ if (subfield == 'renderer' || subfield == 'theme')
+ fetchThemeBundle(setError, setThemeBundle, value.renderer, value.theme);
- const handleTextChange = (text)=>{
//If there are HTML errors, run the validator on every change to give quick feedback
- if(HTMLErrors.length)
- HTMLErrors = Markdown.validate(text);
+ if(HTMLErrors.length && (field == 'text' || field == 'snippets'))
+ setHTMLErrors(Markdown.validate(value));
- setHTMLErrors(HTMLErrors);
- setCurrentBrew((prevBrew) => ({ ...prevBrew, text }));
- localStorage.setItem(BREWKEY, text);
- };
+ if(field == 'metadata') setCurrentBrew(prev => ({ ...prev, ...value }));
+ else setCurrentBrew(prev => ({ ...prev, [field]: value }));
- const handleStyleChange = (style) => {
- setCurrentBrew(prevBrew => ({ ...prevBrew, style }));
- localStorage.setItem(STYLEKEY, style);
- };
-
- const handleSnipChange = (snippet)=>{
- //If there are HTML errors, run the validator on every change to give quick feedback
- if(HTMLErrors.length)
- HTMLErrors = Markdown.validate(snippet);
-
- setHTMLErrors(HTMLErrors);
- setCurrentBrew((prevBrew) => ({ ...prevBrew, snippets: snippet }));
- };
-
- const handleMetaChange = (metadata, field = undefined) => {
- if (field === 'theme' || field === 'renderer')
- fetchThemeBundle(setError, setThemeBundle, metadata.renderer, metadata.theme);
-
- setCurrentBrew(prev => ({ ...prev, ...metadata }));
- localStorage.setItem(METAKEY, JSON.stringify({
- renderer : metadata.renderer,
- theme : metadata.theme,
- lang : metadata.lang
- }));
+ if(useLocalStorage) {
+ if(field == 'text') localStorage.setItem(BREWKEY, value);
+ if(field == 'style') localStorage.setItem(STYLEKEY, value);
+ if(field == 'snippets') localStorage.setItem(SNIPKEY, value);
+ if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
+ renderer : value.renderer,
+ theme : value.theme,
+ lang : value.lang
+ }));
+ }
};
const save = async () => {
@@ -199,8 +185,10 @@ const NewPage = (props) => {
{error
?
: renderSaveButton()}
+
+
@@ -215,15 +203,12 @@ const NewPage = (props) => {
{
themeBundle={themeBundle}
errors={HTMLErrors}
lang={currentBrew.lang}
- onPageChange={handleBrewRendererPageChange}
+ onPageChange={setCurrentBrewRendererPageNum}
currentEditorViewPageNum={currentEditorViewPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
currentBrewRendererPageNum={currentBrewRendererPageNum}
diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js
new file mode 100644
index 000000000..b4a05974f
--- /dev/null
+++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.js
@@ -0,0 +1,35 @@
+
+const getLocalStorageMap = function(){
+ const localStorageMap = {
+ 'AUTOSAVE_ON' : 'HB_editor_autoSaveOn',
+ 'HOMEBREWERY-EDITOR-THEME' : 'HB_editor_theme',
+ 'liveScroll' : 'HB_editor_liveScroll',
+ 'naturalcrit-pane-split' : 'HB_editor_splitWidth',
+
+ 'HOMEBREWERY-LISTPAGE-SORTDIR' : 'HB_listPage_sortDir',
+ 'HOMEBREWERY-LISTPAGE-SORTTYPE' : 'HB_listPage_sortType',
+ 'HOMEBREWERY-LISTPAGE-VISIBILITY-published' : 'HB_listPage_visibility_group_published',
+ 'HOMEBREWERY-LISTPAGE-VISIBILITY-unpublished' : 'HB_listPage_visibility_group_unpublished',
+
+ 'hbAdminTab' : 'HB_adminPage_currentTab',
+
+ 'homebrewery-new' : 'HB_newPage_content',
+ 'homebrewery-new-meta' : 'HB_newPage_metadata',
+ 'homebrewery-new-style' : 'HB_newPage_style',
+
+ 'homebrewery-recently-edited' : 'HB_nav_recentlyEdited',
+ 'homebrewery-recently-viewed' : 'HB_nav_recentlyViewed',
+
+ 'hb_toolbarState' : 'HB_renderer_toolbarState',
+ 'hb_toolbarVisibility' : 'HB_renderer_toolbarVisibility'
+ };
+
+ if(global?.account?.username){
+ const username = global.account.username;
+ localStorageMap[`HOMEBREWERY-DEFAULT-SAVE-LOCATION-${username}`] = `HB_editor_defaultSave_${username}`;
+ }
+
+ return localStorageMap;
+};
+
+export default getLocalStorageMap;
\ No newline at end of file
diff --git a/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js
new file mode 100644
index 000000000..ac61d4add
--- /dev/null
+++ b/client/homebrew/utils/updateLocalStorage/localStorageKeyMap.spec.js
@@ -0,0 +1,30 @@
+import getLocalStorageMap from './localStorageKeyMap.js';
+
+describe('getLocalStorageMap', ()=>{
+ it('no username', ()=>{
+ const account = global.account;
+
+ delete global.account;
+
+ const map = getLocalStorageMap();
+
+ global.account = account;
+
+ expect(map).toBeInstanceOf(Object);
+ expect(Object.entries(map)).toHaveLength(16);
+ });
+
+ it('no username', ()=>{
+ const account = global.account;
+
+ global.account = { username: 'test' };
+
+ const map = getLocalStorageMap();
+
+ global.account = account;
+
+ expect(map).toBeInstanceOf(Object);
+ expect(Object.entries(map)).toHaveLength(17);
+ expect(map).toHaveProperty('HOMEBREWERY-DEFAULT-SAVE-LOCATION-test', 'HB_editor_defaultSave_test');
+ });
+});
\ No newline at end of file
diff --git a/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js
new file mode 100644
index 000000000..1a8231f73
--- /dev/null
+++ b/client/homebrew/utils/updateLocalStorage/updateLocalStorageKeys.js
@@ -0,0 +1,25 @@
+import getLocalStorageMap from './localStorageKeyMap.js';
+
+const updateLocalStorage = function(){
+ // Return if no window and thus no local storage
+ if(typeof window === 'undefined') return;
+
+ // Return if the local storage key map has no content
+ const localStorageKeyMap = getLocalStorageMap();
+ if(Object.keys(localStorageKeyMap).length == 0) return;
+
+ const storage = window.localStorage;
+
+ Object.keys(localStorageKeyMap).forEach((key)=>{
+ if(storage[key]){
+ if(!storage[localStorageKeyMap[key]]){
+ const data = storage.getItem(key);
+ storage.setItem(localStorageKeyMap[key], data);
+ };
+ storage.removeItem(key);
+ }
+ });
+
+};
+
+export { updateLocalStorage };
\ No newline at end of file
diff --git a/server/db.js b/server/db.js
index 8958fa6b2..d7baa922d 100644
--- a/server/db.js
+++ b/server/db.js
@@ -35,8 +35,11 @@ const disconnect = async ()=>{
};
const connect = async (config)=>{
- return await Mongoose.connect(getMongoDBURL(config), { retryWrites: false })
- .then(addListeners(Mongoose))
+ return await Mongoose.connect(getMongoDBURL(config), {
+ retryWrites : false,
+ autoIndex : (config.get('local_environments').includes(config.get('node_env')))
+ })
+ .then(addListeners(Mongoose))
.catch((error)=>handleConnectionError(error));
};
diff --git a/server/homebrew.model.js b/server/homebrew.model.js
index 2e74b1de2..ff371ee42 100644
--- a/server/homebrew.model.js
+++ b/server/homebrew.model.js
@@ -7,29 +7,29 @@ import zlib from 'zlib';
const HomebrewSchema = mongoose.Schema({
shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
editId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } },
- googleId : { type: String },
- title : { type: String, default: '' },
+ googleId : { type: String, index: true },
+ title : { type: String, default: '', index: true },
text : { type: String, default: '' },
textBin : { type: Buffer },
- pageCount : { type: Number, default: 1 },
+ pageCount : { type: Number, default: 1, index: true },
description : { type: String, default: '' },
- tags : [String],
+ tags : { type: [String], index: true },
systems : [String],
- lang : { type: String, default: 'en' },
- renderer : { type: String, default: '' },
- authors : [String],
+ lang : { type: String, default: 'en', index: true },
+ renderer : { type: String, default: '', index: true },
+ authors : { type: [String], index: true },
invitedAuthors : [String],
- published : { type: Boolean, default: false },
- thumbnail : { type: String, default: '' },
+ published : { type: Boolean, default: false, index: true },
+ thumbnail : { type: String, default: '', index: true },
- createdAt : { type: Date, default: Date.now },
- updatedAt : { type: Date, default: Date.now },
- lastViewed : { type: Date, default: Date.now },
+ createdAt : { type: Date, default: Date.now, index: true },
+ updatedAt : { type: Date, default: Date.now, index: true },
+ lastViewed : { type: Date, default: Date.now, index: true },
views : { type: Number, default: 0 },
- version : { type: Number, default: 1 },
+ version : { type: Number, default: 1, index: true },
- lock : { type: Object }
+ lock : { type: Object, index: true }
}, { versionKey: false });
HomebrewSchema.statics.increaseView = async function(query) {
@@ -43,6 +43,8 @@ HomebrewSchema.statics.increaseView = async function(query) {
return brew;
};
+// STATIC FUNCTIONS
+
HomebrewSchema.statics.get = async function(query, fields=null){
const brew = await Homebrew.findOne(query, fields).orFail()
.catch((error)=>{throw 'Can not find brew';});
@@ -63,6 +65,15 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f
return brews;
};
+// INDEXES
+
+HomebrewSchema.index({ updatedAt: -1, lastViewed: -1 });
+HomebrewSchema.index({ published: 1, title: 'text' });
+
+HomebrewSchema.index({ lock: 1, sparse: true });
+HomebrewSchema.path('lock.reviewRequested').index({ sparse: true });
+
+
const Homebrew = mongoose.model('Homebrew', HomebrewSchema);
export {
diff --git a/shared/naturalcrit/codeEditor/codeEditor.less b/shared/naturalcrit/codeEditor/codeEditor.less
index 84a5c63f1..2a57ae8e6 100644
--- a/shared/naturalcrit/codeEditor/codeEditor.less
+++ b/shared/naturalcrit/codeEditor/codeEditor.less
@@ -38,15 +38,6 @@
animation-duration : 0.4s;
}
- .CodeMirror-vscrollbar {
- &::-webkit-scrollbar { width : 20px; }
- &::-webkit-scrollbar-thumb {
- width : 20px;
- background : linear-gradient(90deg, #858585 15px, #808080 15px);
- }
- }
-
-
//.cm-tab {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
//}