mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-09-20 16:42:58 +00:00
Merge branch 'master' into hbfm
This commit is contained in:
+264
-278
@@ -1,8 +1,6 @@
|
|||||||
/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/
|
/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/
|
||||||
import './editor.less';
|
import './editor.less';
|
||||||
import React from 'react';
|
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||||
import createReactClass from 'create-react-class';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import dedent from 'dedent';
|
import dedent from 'dedent';
|
||||||
|
|
||||||
import CodeEditor from '@components/codeEditor/codeEditor.jsx';
|
import CodeEditor from '@components/codeEditor/codeEditor.jsx';
|
||||||
@@ -18,12 +16,8 @@ import cm5Themes from 'codemirror-5-themes';
|
|||||||
const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery };
|
const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery };
|
||||||
|
|
||||||
const EditorThemes = Object.entries(themes)
|
const EditorThemes = Object.entries(themes)
|
||||||
.filter(([name, value])=>Array.isArray(value) &&
|
.filter(([name, value])=>Array.isArray(value) && !name.endsWith('Init') && !name.endsWith('Style'))
|
||||||
!name.endsWith('Init') &&
|
.map(([name])=>name);
|
||||||
!name.endsWith('Style')
|
|
||||||
)
|
|
||||||
.map(([name])=>name);
|
|
||||||
|
|
||||||
|
|
||||||
//const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m;
|
//const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m;
|
||||||
//const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/;
|
//const SNIPPETBREAK_REGEX_V3 = /^\\snippet\ .*$/;
|
||||||
@@ -45,306 +39,298 @@ const DEFAULT_SNIPPET_TEXT = dedent`
|
|||||||
let isJumping = false;
|
let isJumping = false;
|
||||||
let jumpSource = null;
|
let jumpSource = null;
|
||||||
|
|
||||||
const Editor = createReactClass({
|
const Editor = forwardRef(
|
||||||
displayName : 'Editor',
|
(
|
||||||
getDefaultProps : function() {
|
{
|
||||||
return {
|
brew = {},
|
||||||
brew : {
|
|
||||||
text : '',
|
|
||||||
style : ''
|
|
||||||
},
|
|
||||||
|
|
||||||
onBrewChange : ()=>{},
|
onBrewChange = ()=>{},
|
||||||
reportError : ()=>{},
|
reportError = ()=>{},
|
||||||
|
|
||||||
onCursorPageChange : ()=>{},
|
onCursorPageChange = ()=>{},
|
||||||
onViewPageChange : ()=>{},
|
onViewPageChange = ()=>{},
|
||||||
|
|
||||||
editorTheme : 'default',
|
editorTheme = 'default',
|
||||||
renderer : 'legacy',
|
renderer = 'legacy',
|
||||||
|
|
||||||
currentEditorCursorPageNum : 1,
|
moveBrew,
|
||||||
currentEditorViewPageNum : 1,
|
moveSource,
|
||||||
currentBrewRendererPageNum : 1,
|
liveScroll,
|
||||||
};
|
|
||||||
},
|
|
||||||
getInitialState : function() {
|
|
||||||
return {
|
|
||||||
editorTheme : this.props.editorTheme,
|
|
||||||
view : 'text', //'text', 'style', 'meta', 'snippet'
|
|
||||||
snippetBarHeight : 26,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
editor : React.createRef(null),
|
setMoveArrows,
|
||||||
codeEditor : React.createRef(null),
|
updateBrew,
|
||||||
|
showEditButtons,
|
||||||
|
themeBundle,
|
||||||
|
userThemes,
|
||||||
|
|
||||||
isText : function() {return this.state.view == 'text';},
|
currentEditorCursorPageNum = 1,
|
||||||
isStyle : function() {return this.state.view == 'style';},
|
currentEditorViewPageNum = 1,
|
||||||
isMeta : function() {return this.state.view == 'meta';},
|
currentBrewRendererPageNum = 1,
|
||||||
isSnip : function() {return this.state.view == 'snippet';},
|
},
|
||||||
|
ref,
|
||||||
|
)=>{
|
||||||
|
const [currentEditorTheme, setEditorTheme] = useState(editorTheme);
|
||||||
|
const [view, setView] = useState('text'); // 'text', 'style', 'meta', 'snippet'
|
||||||
|
const [snippetBarHeight, setSnippetBarHeight] = useState(26);
|
||||||
|
|
||||||
componentDidMount : function() {
|
const editor = useRef(null);
|
||||||
|
const codeEditor = useRef(null);
|
||||||
|
const throttleBrewMove = useRef(null);
|
||||||
|
|
||||||
const brewRenderer = document.getElementById('BrewRenderer');
|
const isText = ()=>isView('text');
|
||||||
brewRenderer.onload = ()=>brewRenderer.contentDocument?.addEventListener('keydown', this.handleControlKeys);
|
const isStyle = ()=>isView('style');
|
||||||
document.addEventListener('keydown', this.handleControlKeys);
|
const isMeta = ()=>isView('meta');
|
||||||
|
const isSnip = ()=>isView('snippet');
|
||||||
|
|
||||||
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
|
const isView = (name)=>view === name;
|
||||||
if(editorTheme && EditorThemes.includes(editorTheme)) {
|
|
||||||
this.setState({ editorTheme });
|
|
||||||
} else {
|
|
||||||
this.setState({ editorTheme: 'default' });
|
|
||||||
}
|
|
||||||
const snippetBar = document.querySelector('.editor > .snippetBar');
|
|
||||||
if(!snippetBar) return;
|
|
||||||
|
|
||||||
this.resizeObserver = new ResizeObserver((entries)=>{
|
useEffect(()=>{
|
||||||
const height = document.querySelector('.editor > .snippetBar').offsetHeight;
|
const brewRenderer = document.getElementById('BrewRenderer');
|
||||||
this.setState({ snippetBarHeight: height });
|
brewRenderer.onload = ()=>brewRenderer.contentDocument?.addEventListener('keydown', handleControlKeys);
|
||||||
});
|
document.addEventListener('keydown', handleControlKeys);
|
||||||
|
|
||||||
this.resizeObserver.observe(snippetBar);
|
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
|
||||||
},
|
if(editorTheme && EditorThemes.includes(editorTheme)) setEditorTheme(editorTheme); else setEditorTheme('default');
|
||||||
|
const snippetBar = document.querySelector('.editor > .snippetBar');
|
||||||
|
if(!snippetBar) return;
|
||||||
|
|
||||||
componentDidUpdate : function(prevProps, prevState, snapshot) {
|
const resizeObserver = new ResizeObserver((entries)=>{
|
||||||
|
const height = document.querySelector('.editor > .snippetBar').offsetHeight;
|
||||||
|
setSnippetBarHeight(height);
|
||||||
|
});
|
||||||
|
resizeObserver.observe(snippetBar);
|
||||||
|
|
||||||
if(prevProps.moveBrew !== this.props.moveBrew)
|
return ()=>{
|
||||||
this.brewJump();
|
if(resizeObserver) resizeObserver.disconnect();
|
||||||
|
|
||||||
if(prevProps.moveSource !== this.props.moveSource)
|
|
||||||
this.sourceJump();
|
|
||||||
|
|
||||||
if(this.props.liveScroll) {
|
|
||||||
if(prevProps.currentBrewRendererPageNum !== this.props.currentBrewRendererPageNum) {
|
|
||||||
this.sourceJump(this.props.currentBrewRendererPageNum, false);
|
|
||||||
} else if(prevProps.currentEditorViewPageNum !== this.props.currentEditorViewPageNum) {
|
|
||||||
this.brewJump(this.props.currentEditorViewPageNum, false);
|
|
||||||
} else if(prevProps.currentEditorCursorPageNum !== this.props.currentEditorCursorPageNum) {
|
|
||||||
this.brewJump(this.props.currentEditorCursorPageNum, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if(this.resizeObserver) this.resizeObserver.disconnect();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleControlKeys : function(e){
|
|
||||||
if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
|
|
||||||
const LEFTARROW_KEY = 37;
|
|
||||||
const RIGHTARROW_KEY = 39;
|
|
||||||
if(e.keyCode == RIGHTARROW_KEY) this.brewJump();
|
|
||||||
if(e.keyCode == LEFTARROW_KEY) this.sourceJump();
|
|
||||||
if(e.keyCode == LEFTARROW_KEY || e.keyCode == RIGHTARROW_KEY) {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateCurrentCursorPage : function(pageNumber) {
|
|
||||||
this.props.onCursorPageChange(pageNumber);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateCurrentViewPage : function(pageNumber) {
|
|
||||||
this.props.onViewPageChange(pageNumber);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleInject : function(injectText){
|
|
||||||
this.codeEditor.current?.injectText(injectText);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleViewChange : function(newView){
|
|
||||||
this.props.setMoveArrows(newView === 'text');
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
view : newView
|
|
||||||
}, ()=>{
|
|
||||||
this.codeEditor.current?.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){
|
|
||||||
if(!window || !this.isText() || isJumping || jumpSource === 'source')
|
|
||||||
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;
|
|
||||||
|
|
||||||
let scrollingTimeout;
|
|
||||||
const checkIfScrollComplete = ()=>{ // Prevent interrupting a scroll in progress if user clicks multiple times
|
|
||||||
clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
|
|
||||||
scrollingTimeout = setTimeout(()=>{
|
|
||||||
isJumping = false;
|
|
||||||
jumpSource = null;
|
|
||||||
brewRenderer.removeEventListener('scroll', checkIfScrollComplete);
|
|
||||||
}, 150); // If 150 ms pass without a brewRenderer scroll event, assume scrolling is done
|
|
||||||
};
|
|
||||||
|
|
||||||
isJumping = true;
|
|
||||||
jumpSource = 'brew';
|
|
||||||
checkIfScrollComplete();
|
|
||||||
brewRenderer.addEventListener('scroll', checkIfScrollComplete);
|
|
||||||
|
|
||||||
if(smooth) {
|
|
||||||
const bouncePos = targetPos >= 0 ? -30 : 30; //Do a little bounce before scrolling
|
|
||||||
const bounceDelay = 100;
|
|
||||||
const scrollDelay = 500;
|
|
||||||
|
|
||||||
if(!this.throttleBrewMove) {
|
|
||||||
this.throttleBrewMove = _.throttle((currentPos, bouncePos, targetPos)=>{
|
|
||||||
brewRenderer.scrollTo({ top: currentPos + bouncePos, behavior: 'smooth' });
|
|
||||||
setTimeout(()=>{
|
|
||||||
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'smooth', block: 'start' });
|
|
||||||
}, bounceDelay);
|
|
||||||
}, scrollDelay, { leading: true, trailing: false });
|
|
||||||
};
|
};
|
||||||
this.throttleBrewMove(currentPos, bouncePos, targetPos);
|
}, []);
|
||||||
} else {
|
|
||||||
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
sourceJump : function(targetPage=this.props.currentBrewRendererPageNum, smooth=true){
|
useEffect(()=>{ if(moveBrew) brewJump(); }, [moveBrew]);
|
||||||
if(!this.isText() || isJumping || jumpSource === 'brew')
|
useEffect(()=>{ if(moveSource) sourceJump(); }, [moveSource]);
|
||||||
return;
|
useEffect(()=>{ if(liveScroll) sourceJump(currentBrewRendererPageNum, false); }, [currentBrewRendererPageNum, liveScroll]);
|
||||||
|
useEffect(()=>{ if(liveScroll) brewJump(currentEditorViewPageNum, false); }, [currentEditorViewPageNum, liveScroll]);
|
||||||
|
useEffect(()=>{ if(liveScroll) brewJump(currentEditorCursorPageNum, false); }, [currentEditorCursorPageNum, liveScroll]);
|
||||||
|
|
||||||
const editor = this.codeEditor.current;
|
const handleControlKeys = (e)=>{
|
||||||
if(!editor) return;
|
if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
|
||||||
jumpSource = 'source';
|
const LEFTARROW_KEY = 37;
|
||||||
|
const RIGHTARROW_KEY = 39;
|
||||||
|
if(e.keyCode == RIGHTARROW_KEY) brewJump();
|
||||||
|
if(e.keyCode == LEFTARROW_KEY) sourceJump();
|
||||||
|
if(e.keyCode == LEFTARROW_KEY || e.keyCode == RIGHTARROW_KEY) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
editor.scrollToPage(targetPage);
|
const updateCurrentCursorPage = (pageNumber)=>{
|
||||||
setTimeout(()=>{
|
onCursorPageChange(pageNumber);
|
||||||
jumpSource = null;
|
};
|
||||||
}, 200);
|
|
||||||
},
|
|
||||||
|
|
||||||
//Called when there are changes to the editor's dimensions
|
const updateCurrentViewPage = (pageNumber)=>{
|
||||||
update : function(){},
|
onViewPageChange(pageNumber);
|
||||||
|
};
|
||||||
|
|
||||||
updateEditorTheme : function(newTheme){
|
const handleInject = (injectText)=>{
|
||||||
window.localStorage.setItem(EDITOR_THEME_KEY, newTheme);
|
codeEditor.current?.injectText(injectText);
|
||||||
this.setState({
|
};
|
||||||
editorTheme : newTheme
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
//Called by CodeEditor after document switch, so Snippetbar can refresh UndoHistory
|
const handleViewChange = (newView)=>{
|
||||||
rerenderParent : function (){
|
setMoveArrows(newView === 'text');
|
||||||
this.forceUpdate();
|
setView(newView);
|
||||||
},
|
};
|
||||||
|
useEffect(()=>{
|
||||||
|
codeEditor.current?.focus();
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
renderEditor : function(){
|
const brewJump = (targetPage = currentEditorCursorPageNum, smooth = true)=>{
|
||||||
if(this.isText()){
|
if(!window || !isText() || isJumping || jumpSource === 'source') return;
|
||||||
return <>
|
|
||||||
<CodeEditor key='codeEditor'
|
|
||||||
ref={this.codeEditor}
|
|
||||||
language='gfm'
|
|
||||||
tab='brewText'
|
|
||||||
view={this.state.view}
|
|
||||||
value={this.props.brew.text}
|
|
||||||
onChange={this.props.onBrewChange('text')}
|
|
||||||
onCursorChange={(page)=>this.updateCurrentCursorPage(page)}
|
|
||||||
onViewChange={(page)=>this.updateCurrentViewPage(page)}
|
|
||||||
editorTheme={this.state.editorTheme}
|
|
||||||
renderer={this.props.brew.renderer}
|
|
||||||
style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }}/>
|
|
||||||
</>;
|
|
||||||
}
|
|
||||||
if(this.isStyle()){
|
|
||||||
return <>
|
|
||||||
<CodeEditor key='codeEditor'
|
|
||||||
ref={this.codeEditor}
|
|
||||||
language='css'
|
|
||||||
tab='brewStyles'
|
|
||||||
view={this.state.view}
|
|
||||||
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
|
||||||
onChange={this.props.onBrewChange('style')}
|
|
||||||
editorTheme={this.state.editorTheme}
|
|
||||||
renderer={this.props.brew.renderer}
|
|
||||||
style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }}/>
|
|
||||||
</>;
|
|
||||||
}
|
|
||||||
if(this.isMeta()){
|
|
||||||
return <>
|
|
||||||
<CodeEditor key='codeEditor'
|
|
||||||
view={this.state.view}
|
|
||||||
style={{ display: 'none' }}/>
|
|
||||||
<MetadataEditor
|
|
||||||
metadata={this.props.brew}
|
|
||||||
themeBundle={this.props.themeBundle}
|
|
||||||
onChange={this.props.onBrewChange('metadata')}
|
|
||||||
reportError={this.props.reportError}
|
|
||||||
userThemes={this.props.userThemes}/>
|
|
||||||
</>;
|
|
||||||
}
|
|
||||||
if(this.isSnip()){
|
|
||||||
if(!this.props.brew.snippets) { this.props.brew.snippets = DEFAULT_SNIPPET_TEXT; }
|
|
||||||
return <>
|
|
||||||
<CodeEditor key='codeEditor'
|
|
||||||
ref={this.codeEditor}
|
|
||||||
language='gfm'
|
|
||||||
tab='brewSnippets'
|
|
||||||
view={this.state.view}
|
|
||||||
value={this.props.brew.snippets}
|
|
||||||
onChange={this.props.onBrewChange('snippets')}
|
|
||||||
enableFolding={true}
|
|
||||||
editorTheme={this.state.editorTheme}
|
|
||||||
renderer={this.props.brew.renderer}
|
|
||||||
rerenderParent={this.rerenderParent}
|
|
||||||
style={{ height: `calc(100% - 25px)` }}/>
|
|
||||||
</>;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
redo : function(){
|
const brewRenderer =
|
||||||
return this.codeEditor.current?.redo();
|
window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0];
|
||||||
},
|
|
||||||
|
|
||||||
historySize : function(){
|
const currentPos = brewRenderer.scrollTop;
|
||||||
return this.codeEditor.current?.historySize();
|
|
||||||
},
|
|
||||||
|
|
||||||
undo : function(){
|
const targetPos = window.frames['BrewRenderer'].contentDocument
|
||||||
return this.codeEditor.current?.undo();
|
.getElementById(`p${targetPage}`)
|
||||||
},
|
.getBoundingClientRect().top;
|
||||||
|
|
||||||
foldCode : function() {
|
let scrollingTimeout;
|
||||||
return this.codeEditor.current?.foldAll();
|
|
||||||
},
|
const checkIfScrollComplete = ()=>{// Prevent interrupting a scroll in progress if user clicks multiple times
|
||||||
|
clearTimeout(scrollingTimeout);// Reset the timer every time a scroll event occurs
|
||||||
|
|
||||||
|
scrollingTimeout = setTimeout(()=>{
|
||||||
|
isJumping = false;
|
||||||
|
jumpSource = null;
|
||||||
|
|
||||||
|
brewRenderer.removeEventListener('scroll', checkIfScrollComplete);
|
||||||
|
}, 150);// If 150 ms pass without a brewRenderer scroll event, assume scrolling is done
|
||||||
|
};
|
||||||
|
|
||||||
|
isJumping = true;
|
||||||
|
jumpSource = 'brew';
|
||||||
|
|
||||||
|
checkIfScrollComplete();
|
||||||
|
brewRenderer.addEventListener('scroll', checkIfScrollComplete);
|
||||||
|
|
||||||
|
if(smooth) {
|
||||||
|
const bouncePos = targetPos >= 0 ? -30 : 30; //Do a little bounce before scrolling
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if(now - throttleBrewMove.current >= 500) {
|
||||||
|
throttleBrewMove.current = now;
|
||||||
|
|
||||||
|
brewRenderer.scrollTo({ top: currentPos + bouncePos, behavior: 'smooth' });
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'smooth', block: 'start' });
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
brewRenderer.scrollTo({ top : currentPos + targetPos, behavior : 'instant', block : 'start',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sourceJump = (targetPage = currentBrewRendererPageNum, smooth = true)=>{
|
||||||
|
if(!isText() || isJumping || jumpSource === 'brew') return;
|
||||||
|
|
||||||
|
if(!codeEditor.current) return;
|
||||||
|
jumpSource = 'source';
|
||||||
|
|
||||||
|
codeEditor.current.scrollToPage(targetPage);
|
||||||
|
setTimeout(()=>{
|
||||||
|
jumpSource = null;
|
||||||
|
}, 200);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateEditorTheme = (newTheme)=>{
|
||||||
|
window.localStorage.setItem(EDITOR_THEME_KEY, newTheme);
|
||||||
|
setEditorTheme(newTheme);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderEditor = ()=>{
|
||||||
|
if(isText()) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CodeEditor
|
||||||
|
key='codeEditor'
|
||||||
|
ref={codeEditor}
|
||||||
|
language='gfm'
|
||||||
|
tab='brewText'
|
||||||
|
view={view}
|
||||||
|
value={brew.text}
|
||||||
|
onChange={onBrewChange('text')}
|
||||||
|
onCursorChange={(page)=>updateCurrentCursorPage(page)}
|
||||||
|
onViewChange={(page)=>updateCurrentViewPage(page)}
|
||||||
|
editorTheme={currentEditorTheme}
|
||||||
|
renderer={brew.renderer}
|
||||||
|
style={{ height: `calc(100% - ${snippetBarHeight}px)` }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(isStyle()) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CodeEditor
|
||||||
|
key='codeEditor'
|
||||||
|
ref={codeEditor}
|
||||||
|
language='css'
|
||||||
|
tab='brewStyles'
|
||||||
|
view={view}
|
||||||
|
value={brew.style ?? DEFAULT_STYLE_TEXT}
|
||||||
|
onChange={onBrewChange('style')}
|
||||||
|
editorTheme={currentEditorTheme}
|
||||||
|
renderer={brew.renderer}
|
||||||
|
style={{ height: `calc(100% - ${snippetBarHeight}px)` }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(isSnip()) {
|
||||||
|
if(!brew.snippets) {
|
||||||
|
brew.snippets = DEFAULT_SNIPPET_TEXT;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CodeEditor
|
||||||
|
key='codeEditor'
|
||||||
|
ref={codeEditor}
|
||||||
|
language='gfm'
|
||||||
|
tab='brewSnippets'
|
||||||
|
view={view}
|
||||||
|
value={brew.snippets}
|
||||||
|
onChange={onBrewChange('snippets')}
|
||||||
|
enableFolding={true}
|
||||||
|
editorTheme={currentEditorTheme}
|
||||||
|
renderer={brew.renderer}
|
||||||
|
style={{ height: `calc(100% - 25px)` }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(isMeta()) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CodeEditor key='codeEditor' view={view} style={{ display: 'none' }} />
|
||||||
|
<MetadataEditor
|
||||||
|
metadata={brew}
|
||||||
|
themeBundle={themeBundle}
|
||||||
|
onChange={onBrewChange('metadata')}
|
||||||
|
reportError={reportError}
|
||||||
|
userThemes={userThemes}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const redo = ()=>codeEditor.current?.redo();
|
||||||
|
const historySize = ()=>codeEditor.current?.historySize();
|
||||||
|
const undo = ()=>codeEditor.current?.undo();
|
||||||
|
const foldCode = ()=>codeEditor.current?.foldAll();
|
||||||
|
const unfoldCode = ()=>codeEditor.current?.unfoldAll();
|
||||||
|
|
||||||
|
//Called when there are changes to the editor's dimensions
|
||||||
|
const update = ()=>{};
|
||||||
|
|
||||||
|
useImperativeHandle(ref, ()=>({
|
||||||
|
update,
|
||||||
|
undo,
|
||||||
|
redo,
|
||||||
|
foldCode,
|
||||||
|
unfoldCode,
|
||||||
|
historySize,
|
||||||
|
}));
|
||||||
|
|
||||||
unfoldCode : function() {
|
|
||||||
return this.codeEditor.current?.unfoldAll();
|
|
||||||
},
|
|
||||||
render : function(){
|
|
||||||
return (
|
return (
|
||||||
<div className='editor' ref={this.editor}>
|
<div className='editor' ref={editor}>
|
||||||
<SnippetBar
|
<SnippetBar
|
||||||
brew={this.props.brew}
|
brew={brew}
|
||||||
view={this.state.view}
|
view={view}
|
||||||
onViewChange={this.handleViewChange}
|
onViewChange={handleViewChange}
|
||||||
onInject={this.handleInject}
|
onInject={handleInject}
|
||||||
showEditButtons={this.props.showEditButtons}
|
showEditButtons={showEditButtons}
|
||||||
renderer={this.props.renderer}
|
renderer={renderer}
|
||||||
theme={this.props.brew.theme}
|
theme={brew.theme}
|
||||||
undo={this.undo}
|
undo={undo}
|
||||||
redo={this.redo}
|
redo={redo}
|
||||||
foldCode={this.foldCode}
|
foldCode={foldCode}
|
||||||
unfoldCode={this.unfoldCode}
|
unfoldCode={unfoldCode}
|
||||||
historySize={this.historySize()}
|
historySize={historySize()}
|
||||||
currentEditorTheme={this.state.editorTheme}
|
currentEditorTheme={currentEditorTheme}
|
||||||
updateEditorTheme={this.updateEditorTheme}
|
updateEditorTheme={updateEditorTheme}
|
||||||
themeBundle={this.props.themeBundle}
|
themeBundle={themeBundle}
|
||||||
cursorPos={this.codeEditor.current?.getCursorPosition() || {}}
|
cursorPos={codeEditor.current?.getCursorPosition() || {}}
|
||||||
updateBrew={this.props.updateBrew}
|
updateBrew={updateBrew}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.renderEditor()}
|
{renderEditor()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
export default Editor;
|
export default Editor;
|
||||||
|
|||||||
Generated
+26
-30
@@ -16,7 +16,7 @@
|
|||||||
"@babel/preset-react": "^8.0.1",
|
"@babel/preset-react": "^8.0.1",
|
||||||
"@babel/runtime": "^8.0.0",
|
"@babel/runtime": "^8.0.0",
|
||||||
"@codemirror/autocomplete": "^6.20.3",
|
"@codemirror/autocomplete": "^6.20.3",
|
||||||
"@codemirror/commands": "^6.10.3",
|
"@codemirror/commands": "^6.11.0",
|
||||||
"@codemirror/highlight": "^0.19.8",
|
"@codemirror/highlight": "^0.19.8",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-javascript": "^6.2.5",
|
"@codemirror/lang-javascript": "^6.2.5",
|
||||||
@@ -25,11 +25,11 @@
|
|||||||
"@codemirror/language-data": "^6.5.2",
|
"@codemirror/language-data": "^6.5.2",
|
||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.6.0",
|
||||||
"@codemirror/state": "^6.6.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
"@codemirror/view": "^6.43.8",
|
"@codemirror/view": "^6.43.9",
|
||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.2.0",
|
"@googleapis/drive": "^21.0.0",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@oddbird/css-anchor-positioning": "^0.10.1",
|
"@oddbird/css-anchor-positioning": "^0.10.2",
|
||||||
"@sanity/diff-match-patch": "^3.2.0",
|
"@sanity/diff-match-patch": "^3.2.0",
|
||||||
"@vitejs/plugin-react": "^6.0.5",
|
"@vitejs/plugin-react": "^6.0.5",
|
||||||
"body-parser": "^2.3.0",
|
"body-parser": "^2.3.0",
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
"marked-variables": "^1.0.5",
|
"marked-variables": "^1.0.5",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^9.9.2",
|
"mongoose": "^9.9.3",
|
||||||
"nanoid": "6.0.1",
|
"nanoid": "6.0.1",
|
||||||
"nconf": "^0.13.0",
|
"nconf": "^0.13.0",
|
||||||
"node": "^26.7.0",
|
"node": "^26.7.0",
|
||||||
@@ -2633,7 +2633,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.10.4",
|
"version": "6.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.11.0.tgz",
|
||||||
|
"integrity": "sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@@ -3024,7 +3026,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.43.8",
|
"version": "6.43.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.9.tgz",
|
||||||
|
"integrity": "sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.7.0",
|
"@codemirror/state": "^6.7.0",
|
||||||
@@ -3420,7 +3424,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@googleapis/drive": {
|
"node_modules/@googleapis/drive": {
|
||||||
"version": "20.2.0",
|
"version": "21.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-21.0.0.tgz",
|
||||||
|
"integrity": "sha512-vebQpAqn+FZcmDWh1TEQTcYdkKftcSaHc7kO2ZxrINBb+ZMcFu1UybD3+maeqdLs60HrRDYwyzJ6TgZ7/Vn2Rg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"googleapis-common": "^8.0.0"
|
"googleapis-common": "^8.0.0"
|
||||||
@@ -4273,29 +4279,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oddbird/css-anchor-positioning": {
|
"node_modules/@oddbird/css-anchor-positioning": {
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oddbird/css-anchor-positioning/-/css-anchor-positioning-0.10.2.tgz",
|
||||||
|
"integrity": "sha512-sk+1BpF5V+CfFm0CUbyTRxtwsUjcuP6Nz5tOzC6Bh500gBRdJJZJAeQ/3DYKPd9hGge5cqyVfUNl8zpWJVma/Q==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/dom": "^1.7.6",
|
"@floating-ui/dom": "^1.8.0",
|
||||||
"@types/css-tree": "^2.3.11",
|
"@types/css-tree": "^3.2.0",
|
||||||
"css-tree": "^3.2.1",
|
"css-tree": "^3.2.1",
|
||||||
"nanoid": "^5.1.16"
|
"nanoid": "^6.0.1"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@oddbird/css-anchor-positioning/node_modules/nanoid": {
|
|
||||||
"version": "5.1.16",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/ai"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"nanoid": "bin/nanoid.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^18 || >=20"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
@@ -4666,7 +4658,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/css-tree": {
|
"node_modules/@types/css-tree": {
|
||||||
"version": "2.3.11",
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/css-tree/-/css-tree-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-J5KXmk6BFIepOT7280FdFyNs4c5fh0Uee0otjKEvzchrRs38Ii9qminqc4ds0L19X8Zd/rT+brR9jkBthygjWw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/gensync": {
|
"node_modules/@types/gensync": {
|
||||||
@@ -10867,7 +10861,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose": {
|
"node_modules/mongoose": {
|
||||||
"version": "9.9.2",
|
"version": "9.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.9.4.tgz",
|
||||||
|
"integrity": "sha512-Gc7buf0ExrOZ3t8MD8tVzTek7Qr5d+tEwj4GRFmHCtTZvpaDb38EVsXgCkYacPL9ICAftgS+FGe+dQHLRLHhcw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standard-schema/spec": "^1.1.0",
|
"@standard-schema/spec": "^1.1.0",
|
||||||
|
|||||||
+5
-5
@@ -92,7 +92,7 @@
|
|||||||
"@babel/preset-react": "^8.0.1",
|
"@babel/preset-react": "^8.0.1",
|
||||||
"@babel/runtime": "^8.0.0",
|
"@babel/runtime": "^8.0.0",
|
||||||
"@codemirror/autocomplete": "^6.20.3",
|
"@codemirror/autocomplete": "^6.20.3",
|
||||||
"@codemirror/commands": "^6.10.3",
|
"@codemirror/commands": "^6.11.0",
|
||||||
"@codemirror/highlight": "^0.19.8",
|
"@codemirror/highlight": "^0.19.8",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-javascript": "^6.2.5",
|
"@codemirror/lang-javascript": "^6.2.5",
|
||||||
@@ -101,11 +101,11 @@
|
|||||||
"@codemirror/language-data": "^6.5.2",
|
"@codemirror/language-data": "^6.5.2",
|
||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.6.0",
|
||||||
"@codemirror/state": "^6.6.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
"@codemirror/view": "^6.43.8",
|
"@codemirror/view": "^6.43.9",
|
||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.2.0",
|
"@googleapis/drive": "^21.0.0",
|
||||||
"@lezer/highlight": "^1.2.3",
|
"@lezer/highlight": "^1.2.3",
|
||||||
"@oddbird/css-anchor-positioning": "^0.10.1",
|
"@oddbird/css-anchor-positioning": "^0.10.2",
|
||||||
"@sanity/diff-match-patch": "^3.2.0",
|
"@sanity/diff-match-patch": "^3.2.0",
|
||||||
"@vitejs/plugin-react": "^6.0.5",
|
"@vitejs/plugin-react": "^6.0.5",
|
||||||
"body-parser": "^2.3.0",
|
"body-parser": "^2.3.0",
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
"marked-variables": "^1.0.5",
|
"marked-variables": "^1.0.5",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^9.9.2",
|
"mongoose": "^9.9.3",
|
||||||
"nanoid": "6.0.1",
|
"nanoid": "6.0.1",
|
||||||
"nconf": "^0.13.0",
|
"nconf": "^0.13.0",
|
||||||
"node": "^26.7.0",
|
"node": "^26.7.0",
|
||||||
|
|||||||
+26
-20
@@ -2,26 +2,32 @@ import _ from 'lodash';
|
|||||||
|
|
||||||
// Default properties for newly-created brews
|
// Default properties for newly-created brews
|
||||||
const DEFAULT_BREW = {
|
const DEFAULT_BREW = {
|
||||||
title : '',
|
title : '',
|
||||||
text : '',
|
text : '',
|
||||||
style : undefined,
|
style : undefined,
|
||||||
description : '',
|
description : '',
|
||||||
editId : undefined,
|
editId : undefined,
|
||||||
shareId : undefined,
|
shareId : undefined,
|
||||||
createdAt : undefined,
|
createdAt : undefined,
|
||||||
updatedAt : undefined,
|
updatedAt : undefined,
|
||||||
renderer : 'V3',
|
renderer : 'V3',
|
||||||
theme : '5ePHB',
|
theme : '5ePHB',
|
||||||
authors : [],
|
authors : [],
|
||||||
tags : [],
|
tags : [],
|
||||||
lang : 'en',
|
lang : 'en',
|
||||||
thumbnail : '',
|
thumbnail : '',
|
||||||
views : 0,
|
views : 0,
|
||||||
published : false,
|
published : false,
|
||||||
pageCount : 1,
|
pageCount : 1,
|
||||||
gDrive : false,
|
gDrive : false,
|
||||||
trashed : false
|
trashed : false,
|
||||||
|
bleedSize : { top: '.125in', bottom: '.125in', inner: '.125in', outer: '.125in' },
|
||||||
|
safetySpace : { top: '.25in', bottom: '.25in', outer: '.25in', inner: '.5in' },
|
||||||
|
trimSize : { width: '8.5in', height: '11in' },
|
||||||
|
columns : '2',
|
||||||
|
columnGutter : '.125in',
|
||||||
|
license : 'None',
|
||||||
|
legalAuthors : ''
|
||||||
};
|
};
|
||||||
// Default values for older brews with missing properties
|
// Default values for older brews with missing properties
|
||||||
// e.g., missing "renderer" is assumed to be "legacy"
|
// e.g., missing "renderer" is assumed to be "legacy"
|
||||||
|
|||||||
@@ -218,6 +218,14 @@ const api = {
|
|||||||
const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']);
|
const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']);
|
||||||
const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets;
|
const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets;
|
||||||
metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined;
|
metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined;
|
||||||
|
metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer };
|
||||||
|
metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner };
|
||||||
|
metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height };
|
||||||
|
metadata.columns = brew?.columns;
|
||||||
|
metadata.columnGutter = brew?.columnGutter;
|
||||||
|
metadata.license = brew?.license;
|
||||||
|
metadata.legalAuthors = brew?.legalAuthors;
|
||||||
|
|
||||||
text = `\`\`\`metadata\n` +
|
text = `\`\`\`metadata\n` +
|
||||||
`${yaml.dump(metadata)}\n` +
|
`${yaml.dump(metadata)}\n` +
|
||||||
`\`\`\`\n\n` +
|
`\`\`\`\n\n` +
|
||||||
|
|||||||
+243
-36
@@ -359,7 +359,27 @@ describe('Tests for api', ()=>{
|
|||||||
style : undefined,
|
style : undefined,
|
||||||
trashed : false,
|
trashed : false,
|
||||||
updatedAt : undefined,
|
updatedAt : undefined,
|
||||||
views : 0
|
views : 0,
|
||||||
|
bleedSize: {
|
||||||
|
top: '.125in',
|
||||||
|
bottom: '.125in',
|
||||||
|
inner: '.125in',
|
||||||
|
outer: '.125in',
|
||||||
|
},
|
||||||
|
columns: '2',
|
||||||
|
columnGutter: '.125in',
|
||||||
|
legalAuthors: '',
|
||||||
|
license: 'None',
|
||||||
|
safetySpace: {
|
||||||
|
top: '.25in',
|
||||||
|
bottom: '.25in',
|
||||||
|
outer: '.25in',
|
||||||
|
inner: '.5in',
|
||||||
|
},
|
||||||
|
trimSize: {
|
||||||
|
width: '8.5in',
|
||||||
|
height: '11in',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
expect(next).toHaveBeenCalled();
|
expect(next).toHaveBeenCalled();
|
||||||
expect(api.getId).toHaveBeenCalledWith(req);
|
expect(api.getId).toHaveBeenCalledWith(req);
|
||||||
@@ -450,7 +470,27 @@ describe('Tests for api', ()=>{
|
|||||||
tags : ['something', 'fun'],
|
tags : ['something', 'fun'],
|
||||||
renderer : 'v3',
|
renderer : 'v3',
|
||||||
theme : 'phb',
|
theme : 'phb',
|
||||||
googleId : '12345'
|
googleId : '12345',
|
||||||
|
bleedSize: {
|
||||||
|
top: '.125in',
|
||||||
|
bottom: '.125in',
|
||||||
|
inner: '.125in',
|
||||||
|
outer: '.125in',
|
||||||
|
},
|
||||||
|
columns: '2',
|
||||||
|
columnGutter: '.125in',
|
||||||
|
legalAuthors: '',
|
||||||
|
license: 'None',
|
||||||
|
safetySpace: {
|
||||||
|
top: '.25in',
|
||||||
|
bottom: '.25in',
|
||||||
|
outer: '.25in',
|
||||||
|
inner: '.5in',
|
||||||
|
},
|
||||||
|
trimSize: {
|
||||||
|
width: '8.5in',
|
||||||
|
height: '11in',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual(`\`\`\`metadata
|
expect(result).toEqual(`\`\`\`metadata
|
||||||
@@ -461,6 +501,23 @@ tags:
|
|||||||
- fun
|
- fun
|
||||||
renderer: v3
|
renderer: v3
|
||||||
theme: phb
|
theme: phb
|
||||||
|
bleedSize:
|
||||||
|
top: .125in
|
||||||
|
bottom: .125in
|
||||||
|
inner: .125in
|
||||||
|
outer: .125in
|
||||||
|
safetySpace:
|
||||||
|
top: .25in
|
||||||
|
bottom: .25in
|
||||||
|
outer: .25in
|
||||||
|
inner: .5in
|
||||||
|
trimSize:
|
||||||
|
width: 8.5in
|
||||||
|
height: 11in
|
||||||
|
columns: '2'
|
||||||
|
columnGutter: .125in
|
||||||
|
license: None
|
||||||
|
legalAuthors: ''
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@@ -476,7 +533,27 @@ brew`);
|
|||||||
tags : ['something', 'fun'],
|
tags : ['something', 'fun'],
|
||||||
renderer : 'v3',
|
renderer : 'v3',
|
||||||
theme : 'phb',
|
theme : 'phb',
|
||||||
googleId : '12345'
|
googleId : '12345',
|
||||||
|
bleedSize: {
|
||||||
|
top: '.125in',
|
||||||
|
bottom: '.125in',
|
||||||
|
inner: '.125in',
|
||||||
|
outer: '.125in',
|
||||||
|
},
|
||||||
|
columns: '2',
|
||||||
|
columnGutter: '.125in',
|
||||||
|
legalAuthors: '',
|
||||||
|
license: 'None',
|
||||||
|
safetySpace: {
|
||||||
|
top: '.25in',
|
||||||
|
bottom: '.25in',
|
||||||
|
outer: '.25in',
|
||||||
|
inner: '.5in',
|
||||||
|
},
|
||||||
|
trimSize: {
|
||||||
|
width: '8.5in',
|
||||||
|
height: '11in',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual(`\`\`\`metadata
|
expect(result).toEqual(`\`\`\`metadata
|
||||||
@@ -487,6 +564,23 @@ tags:
|
|||||||
- fun
|
- fun
|
||||||
renderer: v3
|
renderer: v3
|
||||||
theme: phb
|
theme: phb
|
||||||
|
bleedSize:
|
||||||
|
top: .125in
|
||||||
|
bottom: .125in
|
||||||
|
inner: .125in
|
||||||
|
outer: .125in
|
||||||
|
safetySpace:
|
||||||
|
top: .25in
|
||||||
|
bottom: .25in
|
||||||
|
outer: .25in
|
||||||
|
inner: .5in
|
||||||
|
trimSize:
|
||||||
|
width: 8.5in
|
||||||
|
height: 11in
|
||||||
|
columns: '2'
|
||||||
|
columnGutter: .125in
|
||||||
|
license: None
|
||||||
|
legalAuthors: ''
|
||||||
|
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@@ -593,16 +687,16 @@ brew`);
|
|||||||
|
|
||||||
expect(res.status).toHaveBeenCalledWith(200);
|
expect(res.status).toHaveBeenCalledWith(200);
|
||||||
expect(res.send).toHaveBeenCalledWith({
|
expect(res.send).toHaveBeenCalledWith({
|
||||||
_id : '1',
|
_id : '1',
|
||||||
authors : ['test user'],
|
authors : ['test user'],
|
||||||
createdAt : undefined,
|
createdAt : undefined,
|
||||||
description : '',
|
description : '',
|
||||||
editId : expect.any(String),
|
editId : expect.any(String),
|
||||||
gDrive : false,
|
gDrive : false,
|
||||||
pageCount : 1,
|
pageCount : 1,
|
||||||
published : false,
|
published : false,
|
||||||
renderer : 'V3',
|
renderer : 'V3',
|
||||||
lang : 'en',
|
lang : 'en',
|
||||||
shareId : expect.any(String),
|
shareId : expect.any(String),
|
||||||
style : undefined,
|
style : undefined,
|
||||||
tags : [],
|
tags : [],
|
||||||
@@ -613,7 +707,27 @@ brew`);
|
|||||||
title : 'asdf',
|
title : 'asdf',
|
||||||
trashed : false,
|
trashed : false,
|
||||||
updatedAt : undefined,
|
updatedAt : undefined,
|
||||||
views : 0
|
views : 0,
|
||||||
|
bleedSize: {
|
||||||
|
top: '.125in',
|
||||||
|
bottom: '.125in',
|
||||||
|
inner: '.125in',
|
||||||
|
outer: '.125in',
|
||||||
|
},
|
||||||
|
columns: '2',
|
||||||
|
columnGutter: '.125in',
|
||||||
|
legalAuthors: '',
|
||||||
|
license: 'None',
|
||||||
|
safetySpace: {
|
||||||
|
top: '.25in',
|
||||||
|
bottom: '.25in',
|
||||||
|
outer: '.25in',
|
||||||
|
inner: '.5in',
|
||||||
|
},
|
||||||
|
trimSize: {
|
||||||
|
width: '8.5in',
|
||||||
|
height: '11in',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -651,28 +765,48 @@ brew`);
|
|||||||
expect(google.newGoogleBrew).toHaveBeenCalled();
|
expect(google.newGoogleBrew).toHaveBeenCalled();
|
||||||
expect(res.status).toHaveBeenCalledWith(200);
|
expect(res.status).toHaveBeenCalledWith(200);
|
||||||
expect(res.send).toHaveBeenCalledWith({
|
expect(res.send).toHaveBeenCalledWith({
|
||||||
_id : '1',
|
_id : '1',
|
||||||
authors : ['test user'],
|
authors : ['test user'],
|
||||||
createdAt : undefined,
|
bleedSize: {
|
||||||
description : '',
|
top: '.125in',
|
||||||
editId : expect.any(String),
|
bottom: '.125in',
|
||||||
gDrive : false,
|
inner: '.125in',
|
||||||
pageCount : 1,
|
outer: '.125in',
|
||||||
published : false,
|
},
|
||||||
renderer : 'V3',
|
columns: '2',
|
||||||
lang : 'en',
|
columnGutter: '.125in',
|
||||||
shareId : expect.any(String),
|
createdAt : undefined,
|
||||||
googleId : expect.any(String),
|
description : '',
|
||||||
style : undefined,
|
editId : expect.any(String),
|
||||||
tags : [],
|
gDrive : false,
|
||||||
text : undefined,
|
pageCount : 1,
|
||||||
textBin : undefined,
|
published : false,
|
||||||
theme : '5ePHB',
|
renderer : 'V3',
|
||||||
thumbnail : '',
|
lang : 'en',
|
||||||
title : 'asdf',
|
shareId : expect.any(String),
|
||||||
trashed : false,
|
legalAuthors: '',
|
||||||
updatedAt : undefined,
|
license: 'None',
|
||||||
views : 0
|
safetySpace: {
|
||||||
|
top: '.25in',
|
||||||
|
bottom: '.25in',
|
||||||
|
outer: '.25in',
|
||||||
|
inner: '.5in',
|
||||||
|
},
|
||||||
|
googleId : expect.any(String),
|
||||||
|
style : undefined,
|
||||||
|
tags : [],
|
||||||
|
text : undefined,
|
||||||
|
textBin : undefined,
|
||||||
|
theme : '5ePHB',
|
||||||
|
thumbnail : '',
|
||||||
|
title : 'asdf',
|
||||||
|
trashed : false,
|
||||||
|
trimSize: {
|
||||||
|
width: '8.5in',
|
||||||
|
height: '11in',
|
||||||
|
},
|
||||||
|
updatedAt : undefined,
|
||||||
|
views : 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1164,6 +1298,79 @@ brew`);
|
|||||||
// Text
|
// Text
|
||||||
expect(testBrew.text).toEqual('text\n');
|
expect(testBrew.text).toEqual('text\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('extended metadata', async ()=>{
|
||||||
|
const testBrew = {
|
||||||
|
text : '```metadata\n' +
|
||||||
|
'title: title\n' +
|
||||||
|
'description: description\n' +
|
||||||
|
'tags: [ \'tag a\' , \'tag b\' ]\n' +
|
||||||
|
'renderer: legacy\n' +
|
||||||
|
'theme: 5ePHB\n' +
|
||||||
|
'lang: en\n' +
|
||||||
|
'bleedSize:\n' +
|
||||||
|
' top: 1.5in\n' +
|
||||||
|
' bottom: 1.5in\n' +
|
||||||
|
' outer: 1.5in\n' +
|
||||||
|
' inner: 1.5in\n' +
|
||||||
|
'safetySpace:\n' +
|
||||||
|
' top: 1.25in\n' +
|
||||||
|
' bottom: 1.25in\n' +
|
||||||
|
' outer: 1.25in\n' +
|
||||||
|
' inner: 1.5in\n' +
|
||||||
|
'trimSize:\n' +
|
||||||
|
' width: 18.5in\n' +
|
||||||
|
' height: 111in\n' +
|
||||||
|
'columns: 12\n' +
|
||||||
|
'columnGutter: 1.125in\n' +
|
||||||
|
'license: AELF\n' +
|
||||||
|
'legalAuthors: Tom Bombadil\n' +
|
||||||
|
'\n' +
|
||||||
|
'```\n' +
|
||||||
|
'\n' +
|
||||||
|
'```css\n' +
|
||||||
|
'style\n' +
|
||||||
|
'style\n' +
|
||||||
|
'style\n' +
|
||||||
|
'```\n' +
|
||||||
|
'\n' +
|
||||||
|
'text\n'
|
||||||
|
};
|
||||||
|
|
||||||
|
splitTextStyleAndMetadata(testBrew);
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
expect(testBrew.title).toEqual('title');
|
||||||
|
expect(testBrew.description).toEqual('description');
|
||||||
|
expect(testBrew.renderer).toEqual('legacy');
|
||||||
|
expect(testBrew.theme).toEqual('5ePHB');
|
||||||
|
expect(testBrew.lang).toEqual('en');
|
||||||
|
// Paper Specfications
|
||||||
|
expect(testBrew.bleedSize.top).toEqual('1.5in');
|
||||||
|
expect(testBrew.bleedSize.bottom).toEqual('1.5in');
|
||||||
|
expect(testBrew.bleedSize.inner).toEqual('1.5in');
|
||||||
|
expect(testBrew.bleedSize.outer).toEqual('1.5in');
|
||||||
|
|
||||||
|
expect(testBrew.safetySpace.top).toEqual('1.25in');
|
||||||
|
expect(testBrew.safetySpace.bottom).toEqual('1.25in');
|
||||||
|
expect(testBrew.safetySpace.inner).toEqual('1.5in');
|
||||||
|
expect(testBrew.safetySpace.outer).toEqual('1.25in');
|
||||||
|
|
||||||
|
expect(testBrew.trimSize.width).toEqual('18.5in');
|
||||||
|
expect(testBrew.trimSize.height).toEqual('111in');
|
||||||
|
|
||||||
|
expect(testBrew.columns).toEqual(12);
|
||||||
|
expect(testBrew.columnGutter).toEqual('1.125in');
|
||||||
|
|
||||||
|
// Extended Metadata
|
||||||
|
expect(testBrew.license).toEqual('AELF');
|
||||||
|
expect(testBrew.legalAuthors).toEqual('Tom Bombadil');
|
||||||
|
|
||||||
|
// Style
|
||||||
|
expect(testBrew.style).toEqual('style\nstyle\nstyle\n');
|
||||||
|
// Text
|
||||||
|
expect(testBrew.text).toEqual('text\n');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -93,6 +93,15 @@ const splitTextStyleAndMetadata = (brew)=>{
|
|||||||
const metadata = yaml.load(metadataSection);
|
const metadata = yaml.load(metadataSection);
|
||||||
Object.assign(brew, _.pick(metadata, ['title', 'description', 'renderer', 'theme', 'lang']));
|
Object.assign(brew, _.pick(metadata, ['title', 'description', 'renderer', 'theme', 'lang']));
|
||||||
brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || '');
|
brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || '');
|
||||||
|
|
||||||
|
brew.bleedSize = { ...metadata.bleedSize };
|
||||||
|
brew.safetySpace = { ...metadata.safetySpace };
|
||||||
|
brew.trimSize = { ...metadata.trimSize };
|
||||||
|
brew.columns = metadata?.columns;
|
||||||
|
brew.columnGutter = metadata?.columnGutter;
|
||||||
|
brew.license = metadata?.license;
|
||||||
|
brew.legalAuthors = metadata.legalAuthors;
|
||||||
|
|
||||||
brew.text = brew.text.slice(index + 6);
|
brew.text = brew.text.slice(index + 6);
|
||||||
}
|
}
|
||||||
if(brew.text.startsWith('```css')) {
|
if(brew.text.startsWith('```css')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user