mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-09-23 09:42:56 +00:00
this is mostly working
This commit is contained in:
+353
-280
@@ -1,29 +1,22 @@
|
|||||||
/*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/
|
import "./editor.less";
|
||||||
import './editor.less';
|
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
|
||||||
import React from 'react';
|
import dedent from "dedent";
|
||||||
import createReactClass from 'create-react-class';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import dedent from 'dedent';
|
|
||||||
|
|
||||||
import CodeEditor from '@components/codeEditor/codeEditor.jsx';
|
import CodeEditor from "@components/codeEditor/codeEditor.jsx";
|
||||||
import SnippetBar from './snippetbar/snippetbar.jsx';
|
import SnippetBar from "./snippetbar/snippetbar.jsx";
|
||||||
import MetadataEditor from './metadataEditor/metadataEditor.jsx';
|
import MetadataEditor from "./metadataEditor/metadataEditor.jsx";
|
||||||
|
|
||||||
const EDITOR_THEME_KEY = 'HB_editor_theme';
|
const EDITOR_THEME_KEY = "HB_editor_theme";
|
||||||
|
|
||||||
import defaultCM5Theme from '@themes/codeMirror/default.js';
|
import defaultCM5Theme from "@themes/codeMirror/default.js";
|
||||||
import darkbrewery from '@themes/codeMirror/darkbrewery.js';
|
import darkbrewery from "@themes/codeMirror/darkbrewery.js";
|
||||||
import cm5Themes from 'codemirror-5-themes';
|
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 +38,386 @@ 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,
|
||||||
|
|
||||||
|
setMoveArrows,
|
||||||
|
updateBrew,
|
||||||
|
showEditButtons,
|
||||||
|
themeBundle,
|
||||||
|
userThemes,
|
||||||
|
|
||||||
|
currentEditorCursorPageNum = 1,
|
||||||
|
currentEditorViewPageNum = 1,
|
||||||
|
currentBrewRendererPageNum = 1,
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const [currentEditorTheme, setEditorTheme] = useState(editorTheme);
|
||||||
|
const [view, setView] = useState("text"); // 'text', 'style', 'meta', 'snippet'
|
||||||
|
const [snippetBarHeight, setSnippetBarHeight] = useState(26);
|
||||||
|
|
||||||
|
const editor = useRef(null);
|
||||||
|
const codeEditor = useRef(null);
|
||||||
|
const throttleBrewMove = useRef(null);
|
||||||
|
|
||||||
|
const isText = () => {
|
||||||
|
return view === "text";
|
||||||
};
|
};
|
||||||
},
|
const isStyle = () => {
|
||||||
getInitialState : function() {
|
return view === "style";
|
||||||
return {
|
};
|
||||||
editorTheme : this.props.editorTheme,
|
const isMeta = () => {
|
||||||
view : 'text', //'text', 'style', 'meta', 'snippet'
|
return view === "meta";
|
||||||
snippetBarHeight : 26,
|
};
|
||||||
|
const isSnip = () => {
|
||||||
|
return view === "snippet";
|
||||||
};
|
};
|
||||||
},
|
|
||||||
|
|
||||||
editor : React.createRef(null),
|
//componentDidMount equivalent
|
||||||
codeEditor : React.createRef(null),
|
useEffect(() => {
|
||||||
|
const brewRenderer = document.getElementById("BrewRenderer");
|
||||||
|
brewRenderer.onload = () => brewRenderer.contentDocument?.addEventListener("keydown", handleControlKeys);
|
||||||
|
document.addEventListener("keydown", handleControlKeys);
|
||||||
|
|
||||||
isText : function() {return this.state.view == 'text';},
|
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
|
||||||
isStyle : function() {return this.state.view == 'style';},
|
if (editorTheme && EditorThemes.includes(editorTheme)) {
|
||||||
isMeta : function() {return this.state.view == 'meta';},
|
setEditorTheme(editorTheme);
|
||||||
isSnip : function() {return this.state.view == 'snippet';},
|
} else {
|
||||||
|
setEditorTheme("default");
|
||||||
componentDidMount : function() {
|
|
||||||
|
|
||||||
const brewRenderer = document.getElementById('BrewRenderer');
|
|
||||||
brewRenderer.onload = ()=>brewRenderer.contentDocument?.addEventListener('keydown', this.handleControlKeys);
|
|
||||||
document.addEventListener('keydown', this.handleControlKeys);
|
|
||||||
|
|
||||||
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
|
|
||||||
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)=>{
|
|
||||||
const height = document.querySelector('.editor > .snippetBar').offsetHeight;
|
|
||||||
this.setState({ snippetBarHeight: height });
|
|
||||||
});
|
|
||||||
|
|
||||||
this.resizeObserver.observe(snippetBar);
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate : function(prevProps, prevState, snapshot) {
|
|
||||||
|
|
||||||
if(prevProps.moveBrew !== this.props.moveBrew)
|
|
||||||
this.brewJump();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
const snippetBar = document.querySelector(".editor > .snippetBar");
|
||||||
},
|
if (!snippetBar) return;
|
||||||
|
|
||||||
componentWillUnmount() {
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
if(this.resizeObserver) this.resizeObserver.disconnect();
|
const height = document.querySelector(".editor > .snippetBar").offsetHeight;
|
||||||
},
|
setSnippetBarHeight(height);
|
||||||
|
});
|
||||||
|
|
||||||
handleControlKeys : function(e){
|
resizeObserver.observe(snippetBar);
|
||||||
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) {
|
//ComponentWillUnmount equivalent
|
||||||
this.props.onCursorPageChange(pageNumber);
|
return () => {
|
||||||
},
|
if (resizeObserver) resizeObserver.disconnect();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
updateCurrentViewPage : function(pageNumber) {
|
const previousProps = useRef({
|
||||||
this.props.onViewPageChange(pageNumber);
|
moveBrew,
|
||||||
},
|
moveSource,
|
||||||
|
currentBrewRendererPageNum,
|
||||||
handleInject : function(injectText){
|
currentEditorViewPageNum,
|
||||||
this.codeEditor.current?.injectText(injectText);
|
currentEditorCursorPageNum,
|
||||||
},
|
|
||||||
|
|
||||||
handleViewChange : function(newView){
|
|
||||||
this.props.setMoveArrows(newView === 'text');
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
view : newView
|
|
||||||
}, ()=>{
|
|
||||||
this.codeEditor.current?.focus();
|
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){
|
//componentDidUpdate Equivalent
|
||||||
if(!window || !this.isText() || isJumping || jumpSource === 'source')
|
useEffect(() => {
|
||||||
return;
|
const prev = previousProps.current;
|
||||||
|
|
||||||
// Get current brewRenderer scroll position and calculate target position
|
if (prev.moveBrew !== moveBrew) {
|
||||||
const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0];
|
brewJump();
|
||||||
const currentPos = brewRenderer.scrollTop;
|
}
|
||||||
const targetPos = window.frames['BrewRenderer'].contentDocument.getElementById(`p${targetPage}`).getBoundingClientRect().top;
|
|
||||||
|
|
||||||
let scrollingTimeout;
|
if (prev.moveSource !== moveSource) {
|
||||||
const checkIfScrollComplete = ()=>{ // Prevent interrupting a scroll in progress if user clicks multiple times
|
sourceJump();
|
||||||
clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
|
}
|
||||||
scrollingTimeout = setTimeout(()=>{
|
|
||||||
isJumping = false;
|
if (liveScroll) {
|
||||||
jumpSource = null;
|
if (prev.currentBrewRendererPageNum !== currentBrewRendererPageNum) {
|
||||||
brewRenderer.removeEventListener('scroll', checkIfScrollComplete);
|
sourceJump(currentBrewRendererPageNum, false);
|
||||||
}, 150); // If 150 ms pass without a brewRenderer scroll event, assume scrolling is done
|
} else if (prev.currentEditorViewPageNum !== currentEditorViewPageNum) {
|
||||||
|
brewJump(currentEditorViewPageNum, false);
|
||||||
|
} else if (prev.currentEditorCursorPageNum !== currentEditorCursorPageNum) {
|
||||||
|
brewJump(currentEditorCursorPageNum, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousProps.current = {
|
||||||
|
moveBrew,
|
||||||
|
moveSource,
|
||||||
|
currentBrewRendererPageNum,
|
||||||
|
currentEditorViewPageNum,
|
||||||
|
currentEditorCursorPageNum,
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
moveBrew,
|
||||||
|
moveSource,
|
||||||
|
liveScroll,
|
||||||
|
currentBrewRendererPageNum,
|
||||||
|
currentEditorViewPageNum,
|
||||||
|
currentEditorCursorPageNum,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleControlKeys = (e) => {
|
||||||
|
if (!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const updateCurrentCursorPage = (pageNumber) => {
|
||||||
|
onCursorPageChange(pageNumber);
|
||||||
};
|
};
|
||||||
|
|
||||||
isJumping = true;
|
const updateCurrentViewPage = (pageNumber) => {
|
||||||
jumpSource = 'brew';
|
onViewPageChange(pageNumber);
|
||||||
checkIfScrollComplete();
|
};
|
||||||
brewRenderer.addEventListener('scroll', checkIfScrollComplete);
|
|
||||||
|
|
||||||
if(smooth) {
|
const handleInject = (injectText) => {
|
||||||
const bouncePos = targetPos >= 0 ? -30 : 30; //Do a little bounce before scrolling
|
codeEditor.current?.injectText(injectText);
|
||||||
const bounceDelay = 100;
|
};
|
||||||
const scrollDelay = 500;
|
|
||||||
|
|
||||||
if(!this.throttleBrewMove) {
|
const handleViewChange = (newView) => {
|
||||||
this.throttleBrewMove = _.throttle((currentPos, bouncePos, targetPos)=>{
|
setMoveArrows(newView === "text");
|
||||||
brewRenderer.scrollTo({ top: currentPos + bouncePos, behavior: 'smooth' });
|
setView(newView);
|
||||||
setTimeout(()=>{
|
};
|
||||||
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'smooth', block: 'start' });
|
|
||||||
}, bounceDelay);
|
useEffect(() => {
|
||||||
}, scrollDelay, { leading: true, trailing: false });
|
codeEditor.current?.focus();
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
|
const brewJump = (targetPage = currentEditorCursorPageNum, smooth = true) => {
|
||||||
|
if (!window || !isText() || isJumping || jumpSource === "source") return;
|
||||||
|
|
||||||
|
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 = () => {
|
||||||
|
clearTimeout(scrollingTimeout);
|
||||||
|
|
||||||
|
scrollingTimeout = setTimeout(() => {
|
||||||
|
isJumping = false;
|
||||||
|
jumpSource = null;
|
||||||
|
|
||||||
|
brewRenderer.removeEventListener("scroll", checkIfScrollComplete);
|
||||||
|
}, 150);
|
||||||
};
|
};
|
||||||
this.throttleBrewMove(currentPos, bouncePos, targetPos);
|
|
||||||
} else {
|
|
||||||
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
sourceJump : function(targetPage=this.props.currentBrewRendererPageNum, smooth=true){
|
isJumping = true;
|
||||||
if(!this.isText() || isJumping || jumpSource === 'brew')
|
jumpSource = "brew";
|
||||||
return;
|
|
||||||
|
|
||||||
const editor = this.codeEditor.current;
|
checkIfScrollComplete();
|
||||||
if(!editor) return;
|
|
||||||
jumpSource = 'source';
|
|
||||||
|
|
||||||
editor.scrollToPage(targetPage);
|
brewRenderer.addEventListener("scroll", checkIfScrollComplete);
|
||||||
setTimeout(()=>{
|
|
||||||
jumpSource = null;
|
|
||||||
}, 200);
|
|
||||||
},
|
|
||||||
|
|
||||||
//Called when there are changes to the editor's dimensions
|
if (smooth) {
|
||||||
update : function(){},
|
const bouncePos = targetPos >= 0 ? -30 : 30;
|
||||||
|
const bounceDelay = 100;
|
||||||
|
const scrollDelay = 500;
|
||||||
|
|
||||||
updateEditorTheme : function(newTheme){
|
if (!throttleBrewMove.current) {
|
||||||
window.localStorage.setItem(EDITOR_THEME_KEY, newTheme);
|
throttleBrewMove.current = _.throttle(
|
||||||
this.setState({
|
(currentPos, bouncePos, targetPos) => {
|
||||||
editorTheme : newTheme
|
brewRenderer.scrollTo({
|
||||||
});
|
top: currentPos + bouncePos,
|
||||||
},
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
|
||||||
//Called by CodeEditor after document switch, so Snippetbar can refresh UndoHistory
|
setTimeout(() => {
|
||||||
rerenderParent : function (){
|
brewRenderer.scrollTo({
|
||||||
this.forceUpdate();
|
top: currentPos + targetPos,
|
||||||
},
|
behavior: "smooth",
|
||||||
|
block: "start",
|
||||||
|
});
|
||||||
|
}, bounceDelay);
|
||||||
|
},
|
||||||
|
scrollDelay,
|
||||||
|
{
|
||||||
|
leading: true,
|
||||||
|
trailing: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderEditor : function(){
|
throttleBrewMove.current(currentPos, bouncePos, targetPos);
|
||||||
if(this.isText()){
|
} else {
|
||||||
return <>
|
brewRenderer.scrollTo({
|
||||||
<CodeEditor key='codeEditor'
|
top: currentPos + targetPos,
|
||||||
ref={this.codeEditor}
|
behavior: "instant",
|
||||||
language='gfm'
|
block: "start",
|
||||||
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 sourceJump = (targetPage = currentBrewRendererPageNum, smooth = true) => {
|
||||||
return this.codeEditor.current?.redo();
|
if (!isText() || isJumping || jumpSource === "brew") return;
|
||||||
},
|
|
||||||
|
|
||||||
historySize : function(){
|
const editor = codeEditor.current;
|
||||||
return this.codeEditor.current?.historySize();
|
if (!editor) return;
|
||||||
},
|
jumpSource = "source";
|
||||||
|
|
||||||
undo : function(){
|
editor.scrollToPage(targetPage);
|
||||||
return this.codeEditor.current?.undo();
|
setTimeout(() => {
|
||||||
},
|
jumpSource = null;
|
||||||
|
}, 200);
|
||||||
|
};
|
||||||
|
|
||||||
foldCode : function() {
|
const updateEditorTheme = (newTheme) => {
|
||||||
return this.codeEditor.current?.foldAll();
|
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 (isMeta()) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CodeEditor key="codeEditor" view={view} style={{ display: "none" }} />
|
||||||
|
<MetadataEditor
|
||||||
|
metadata={brew}
|
||||||
|
themeBundle={themeBundle}
|
||||||
|
onChange={onBrewChange("metadata")}
|
||||||
|
reportError={reportError}
|
||||||
|
userThemes={userThemes}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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}
|
||||||
|
rerenderParent={rerenderParent}
|
||||||
|
style={{ height: `calc(100% - 25px)` }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const redo = () => {
|
||||||
|
return codeEditor.current?.redo();
|
||||||
|
};
|
||||||
|
|
||||||
|
const historySize = () => {
|
||||||
|
return codeEditor.current?.historySize();
|
||||||
|
};
|
||||||
|
|
||||||
|
const undo = () => {
|
||||||
|
return codeEditor.current?.undo();
|
||||||
|
};
|
||||||
|
|
||||||
|
const foldCode = () => {
|
||||||
|
return codeEditor.current?.foldAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
const unfoldCode = () => {
|
||||||
|
return codeEditor.current?.unfoldAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
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={editorTheme}
|
||||||
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;
|
||||||
Reference in New Issue
Block a user