mirror of
https://github.com/stolksdorf/homebrewery.git
synced 2026-01-06 09:29:15 +00:00
Merge branch 'styleEditor' into noHtml
This commit is contained in:
@@ -33,7 +33,7 @@ const ContinousSave = React.createClass({
|
||||
window.onbeforeunload = function(){};
|
||||
},
|
||||
actionHandler : function(actionType){
|
||||
if(actionType == 'UPDATE_BREW_TEXT' || actionType == 'UPDATE_META'){
|
||||
if(actionType == 'UPDATE_BREW_CODE' || actionType == 'UPDATE_META' || actionType == 'UPDATE_BREW_STYLE'){
|
||||
Actions.pendingSave();
|
||||
}
|
||||
},
|
||||
@@ -51,6 +51,9 @@ const ContinousSave = React.createClass({
|
||||
Oops!
|
||||
<div className='errorContainer'>
|
||||
Looks like there was a problem saving. <br />
|
||||
Back up your brew in a text file, just in case.
|
||||
<br /><br />
|
||||
|
||||
Report the issue <a target='_blank' href={'https://github.com/stolksdorf/naturalcrit/issues/new?body='+ encodeURIComponent(errMsg)}>
|
||||
here
|
||||
</a>.
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
top : 29px;
|
||||
left : -20px;
|
||||
z-index : 1000;
|
||||
width : 120px;
|
||||
width : 170px;
|
||||
padding : 8px;
|
||||
background-color : #333;
|
||||
a{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"codemirror",
|
||||
"codemirror/mode/gfm/gfm.js",
|
||||
"codemirror/mode/javascript/javascript.js",
|
||||
"codemirror/mode/css/css.js",
|
||||
"moment",
|
||||
"superagent",
|
||||
"marked",
|
||||
|
||||
@@ -10,6 +10,7 @@ const BrewSchema = mongoose.Schema({
|
||||
editId : {type : String, default: shortid.generate, index: { unique: true }},
|
||||
|
||||
text : {type : String, default : ""},
|
||||
style : {type : String, default : ""},
|
||||
|
||||
title : {type : String, default : ""},
|
||||
description : {type : String, default : ""},
|
||||
@@ -23,7 +24,7 @@ const BrewSchema = mongoose.Schema({
|
||||
updatedAt : { type: Date, default: Date.now},
|
||||
lastViewed : { type: Date, default: Date.now},
|
||||
views : {type:Number, default:0},
|
||||
version : {type: Number, default:1}
|
||||
version : {type: Number, default:2}
|
||||
}, {
|
||||
versionKey: false,
|
||||
toJSON : {
|
||||
|
||||
@@ -54,10 +54,13 @@ const Actions = {
|
||||
setBrew : (brew) => {
|
||||
dispatch('SET_BREW', brew);
|
||||
},
|
||||
updateBrewText : (brewText) => {
|
||||
dispatch('UPDATE_BREW_TEXT', brewText)
|
||||
updateBrewCode : (brewCode) => {
|
||||
dispatch('UPDATE_BREW_CODE', brewCode)
|
||||
},
|
||||
updateMetaData : (meta) => {
|
||||
updateBrewStyle : (style) => {
|
||||
dispatch('UPDATE_BREW_STYLE', style)
|
||||
},
|
||||
updateMetadata : (meta) => {
|
||||
dispatch('UPDATE_META', meta);
|
||||
},
|
||||
pendingSave : () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ let State = {
|
||||
|
||||
brew : {
|
||||
text : '',
|
||||
style : '',
|
||||
shareId : undefined,
|
||||
editId : undefined,
|
||||
createdAt : undefined,
|
||||
@@ -29,9 +30,13 @@ const Store = flux.createStore({
|
||||
SET_BREW : (brew) => {
|
||||
State.brew = brew;
|
||||
},
|
||||
UPDATE_BREW_TEXT : (brewText) => {
|
||||
State.brew.text = brewText;
|
||||
State.errors = Markdown.validate(brewText);
|
||||
UPDATE_BREW_CODE : (brewCode) => {
|
||||
State.brew.text = brewCode;
|
||||
State.errors = Markdown.validate(brewCode);
|
||||
},
|
||||
UPDATE_BREW_STYLE : (style) => {
|
||||
//TODO: add in an error checker?
|
||||
State.brew.style = style;
|
||||
},
|
||||
UPDATE_META : (meta) => {
|
||||
State.brew = _.merge({}, State.brew, meta);
|
||||
@@ -50,11 +55,14 @@ Store.init = (state)=>{
|
||||
Store.getBrew = ()=>{
|
||||
return State.brew;
|
||||
};
|
||||
Store.getBrewText = ()=>{
|
||||
Store.getBrewCode = ()=>{
|
||||
return State.brew.text;
|
||||
};
|
||||
Store.getBrewStyle = ()=>{
|
||||
return State.brew.style;
|
||||
};
|
||||
Store.getMetaData = ()=>{
|
||||
return _.omit(State.brew, ['text']);
|
||||
return _.omit(State.brew, ['text', 'style']);
|
||||
};
|
||||
Store.getErrors = ()=>{
|
||||
return State.errors;
|
||||
|
||||
@@ -6,35 +6,36 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
||||
const SnippetBar = require('./snippetbar/snippetbar.jsx');
|
||||
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
|
||||
|
||||
const Menubar = require('./menubar/menubar.jsx');
|
||||
|
||||
const splice = function(str, index, inject){
|
||||
return str.slice(0, index) + inject + str.slice(index);
|
||||
};
|
||||
|
||||
const SNIPPETBAR_HEIGHT = 25;
|
||||
const MENUBAR_HEIGHT = 25;
|
||||
|
||||
const BrewEditor = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
value : '',
|
||||
onChange : ()=>{},
|
||||
brew : {
|
||||
text : '',
|
||||
style : '',
|
||||
},
|
||||
|
||||
metadata : {},
|
||||
onMetadataChange : ()=>{},
|
||||
onCodeChange : ()=>{},
|
||||
onStyleChange : ()=>{},
|
||||
onMetaChange : ()=>{},
|
||||
};
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showMetadataEditor: false
|
||||
view : 'code', //'code', 'style', 'meta'
|
||||
};
|
||||
},
|
||||
cursorPosition : {
|
||||
line : 0,
|
||||
ch : 0
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.updateEditorSize();
|
||||
this.highlightPageLines();
|
||||
//this.highlightPageLines();
|
||||
window.addEventListener("resize", this.updateEditorSize);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
@@ -42,17 +43,15 @@ const BrewEditor = React.createClass({
|
||||
},
|
||||
|
||||
updateEditorSize : function() {
|
||||
let paneHeight = this.refs.main.parentNode.clientHeight;
|
||||
paneHeight -= SNIPPETBAR_HEIGHT + 1;
|
||||
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
|
||||
if(this.refs.codeEditor){
|
||||
let paneHeight = this.refs.main.parentNode.clientHeight;
|
||||
paneHeight -= MENUBAR_HEIGHT + 1;
|
||||
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
|
||||
}
|
||||
},
|
||||
|
||||
handleTextChange : function(text){
|
||||
this.props.onChange(text);
|
||||
},
|
||||
handleCursorActivty : function(curpos){
|
||||
this.cursorPosition = curpos;
|
||||
},
|
||||
|
||||
|
||||
handleInject : function(injectText){
|
||||
const lines = this.props.value.split('\n');
|
||||
lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText);
|
||||
@@ -60,23 +59,32 @@ const BrewEditor = React.createClass({
|
||||
this.handleTextChange(lines.join('\n'));
|
||||
this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length);
|
||||
},
|
||||
handgleToggle : function(){
|
||||
|
||||
|
||||
|
||||
handleViewChange : function(newView){
|
||||
this.setState({
|
||||
showMetadataEditor : !this.state.showMetadataEditor
|
||||
})
|
||||
view : newView
|
||||
}, this.updateEditorSize);
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
brewJump : function(){
|
||||
const currentPage = this.getCurrentPage();
|
||||
window.location.hash = 'p' + currentPage;
|
||||
},
|
||||
|
||||
//Called when there are changes to the editor's dimensions
|
||||
/*
|
||||
update : function(){
|
||||
this.refs.codeEditor.updateSize();
|
||||
if(this.refs.codeEditor) this.refs.codeEditor.updateSize();
|
||||
},
|
||||
*/
|
||||
|
||||
//TODO: convert this into a generic function for columns and blocks
|
||||
//MOve this to a util.sj file
|
||||
highlightPageLines : function(){
|
||||
if(!this.refs.codeEditor) return;
|
||||
const codeMirror = this.refs.codeEditor.codeMirror;
|
||||
@@ -91,6 +99,7 @@ const BrewEditor = React.createClass({
|
||||
return lineNumbers
|
||||
},
|
||||
|
||||
/*
|
||||
renderMetadataEditor : function(){
|
||||
if(!this.state.showMetadataEditor) return;
|
||||
return <MetadataEditor
|
||||
@@ -98,25 +107,49 @@ const BrewEditor = React.createClass({
|
||||
onChange={this.props.onMetadataChange}
|
||||
/>
|
||||
},
|
||||
*/
|
||||
|
||||
|
||||
|
||||
renderEditor : function(){
|
||||
if(this.state.view == 'meta'){
|
||||
return <MetadataEditor
|
||||
metadata={this.props.brew}
|
||||
onChange={this.props.onMetaChange} />
|
||||
}
|
||||
if(this.state.view == 'style'){
|
||||
return <CodeEditor key='style'
|
||||
ref='codeEditor'
|
||||
language='css'
|
||||
value={this.props.brew.style}
|
||||
onChange={this.props.onStyleChange} />
|
||||
}
|
||||
if(this.state.view == 'code'){
|
||||
return <CodeEditor key='code'
|
||||
ref='codeEditor'
|
||||
language='gfm'
|
||||
value={this.props.brew.text}
|
||||
onChange={this.props.onCodeChange} />
|
||||
}
|
||||
},
|
||||
|
||||
render : function(){
|
||||
|
||||
this.highlightPageLines();
|
||||
|
||||
return<div className='brewEditor' ref='main'>
|
||||
return <div className='brewEditor' ref='main'>
|
||||
{/*
|
||||
<SnippetBar
|
||||
brew={this.props.value}
|
||||
onInject={this.handleInject}
|
||||
onToggle={this.handgleToggle}
|
||||
showmeta={this.state.showMetadataEditor} />
|
||||
{this.renderMetadataEditor()}
|
||||
<CodeEditor
|
||||
ref='codeEditor'
|
||||
wrap={true}
|
||||
language='gfm'
|
||||
value={this.props.value}
|
||||
onChange={this.handleTextChange}
|
||||
onCursorActivity={this.handleCursorActivty} />
|
||||
*/}
|
||||
<Menubar
|
||||
view={this.state.view}
|
||||
onViewChange={this.handleViewChange}
|
||||
|
||||
/>
|
||||
|
||||
{this.renderEditor()}
|
||||
|
||||
</div>
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,9 +5,10 @@ const BrewEditor = require('./brewEditor.jsx')
|
||||
|
||||
module.exports = Store.createSmartComponent(BrewEditor, ()=>{
|
||||
return {
|
||||
value : Store.getBrewText(),
|
||||
onChange : Actions.updateBrewText,
|
||||
metadata : Store.getMetaData(),
|
||||
onMetadataChange : Actions.updateMetaData,
|
||||
brew : Store.getBrew(),
|
||||
|
||||
onCodeChange : Actions.updateBrewCode,
|
||||
onStyleChange : Actions.updateBrewStyle,
|
||||
onMetaChange : Actions.updateMetadata,
|
||||
};
|
||||
});
|
||||
35
shared/homebrewery/brewEditor/menubar/menubar.jsx
Normal file
35
shared/homebrewery/brewEditor/menubar/menubar.jsx
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
const React = require('react');
|
||||
const _ = require('lodash');
|
||||
const cx = require('classnames');
|
||||
|
||||
const Menubar = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
view : '',
|
||||
onViewChange : ()=>{},
|
||||
onSnippetInject : ()=>{},
|
||||
};
|
||||
},
|
||||
render: function(){
|
||||
return <div className='menubar'>
|
||||
|
||||
<div className='editors'>
|
||||
<div className={cx('code', {selected : this.props.view == 'code'})}
|
||||
onClick={this.props.onViewChange.bind(null, 'code')}>
|
||||
<i className='fa fa-beer' />
|
||||
</div>
|
||||
<div className={cx('style', {selected : this.props.view == 'style'})}
|
||||
onClick={this.props.onViewChange.bind(null, 'style')}>
|
||||
<i className='fa fa-paint-brush' />
|
||||
</div>
|
||||
<div className={cx('meta', {selected : this.props.view == 'meta'})}
|
||||
onClick={this.props.onViewChange.bind(null, 'meta')}>
|
||||
<i className='fa fa-bars' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Menubar;
|
||||
35
shared/homebrewery/brewEditor/menubar/menubar.less
Normal file
35
shared/homebrewery/brewEditor/menubar/menubar.less
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
.menubar{
|
||||
@menuHeight : 25px;
|
||||
position : relative;
|
||||
height : @menuHeight;
|
||||
background-color : #ddd;
|
||||
.editors{
|
||||
position : absolute;
|
||||
display : flex;
|
||||
top : 0px;
|
||||
right : 0px;
|
||||
height : @menuHeight;
|
||||
width : 90px;
|
||||
justify-content : space-between;
|
||||
&>div{
|
||||
height : @menuHeight;
|
||||
width : @menuHeight;
|
||||
cursor : pointer;
|
||||
line-height : @menuHeight;
|
||||
text-align : center;
|
||||
&:hover,&.selected{
|
||||
background-color : #999;
|
||||
}
|
||||
&.code{
|
||||
.tooltipLeft('Brew Editor');
|
||||
}
|
||||
&.style{
|
||||
.tooltipLeft('Style Editor');
|
||||
}
|
||||
&.meta{
|
||||
.tooltipLeft('Metadata');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
.metadataEditor{
|
||||
position : absolute;
|
||||
z-index : 10000;
|
||||
box-sizing : border-box;
|
||||
width : 100%;
|
||||
padding : 25px;
|
||||
background-color : #999;
|
||||
// background-color : #999;
|
||||
background-color: white;
|
||||
.field{
|
||||
display : flex;
|
||||
width : 100%;
|
||||
|
||||
@@ -15,12 +15,13 @@ const PPR_THRESHOLD = 50;
|
||||
const BrewRenderer = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
brewText : '',
|
||||
value : '',
|
||||
style : '',
|
||||
errors : []
|
||||
};
|
||||
},
|
||||
getInitialState: function() {
|
||||
const pages = this.props.brewText.split('\\page');
|
||||
const pages = this.props.value.split('\\page');
|
||||
|
||||
return {
|
||||
viewablePageNumber: 0,
|
||||
@@ -45,7 +46,7 @@ const BrewRenderer = React.createClass({
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
if(this.refs.pages && this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight;
|
||||
|
||||
const pages = nextProps.brewText.split('\\page');
|
||||
const pages = nextProps.value.split('\\page');
|
||||
this.setState({
|
||||
pages : pages,
|
||||
usePPR : pages.length >= PPR_THRESHOLD
|
||||
@@ -124,6 +125,10 @@ const BrewRenderer = React.createClass({
|
||||
return this.lastRender;
|
||||
},
|
||||
|
||||
renderStyle : function(){
|
||||
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className='brewRenderer'
|
||||
onScroll={this.handleScroll}
|
||||
@@ -133,6 +138,8 @@ const BrewRenderer = React.createClass({
|
||||
<ErrorBar errors={this.props.errors} />
|
||||
<RenderWarnings />
|
||||
|
||||
|
||||
<style>{this.props.style}</style>
|
||||
<div className='pages' ref='pages'>
|
||||
{this.renderPages()}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,8 @@ const BrewRenderer = require('./brewRenderer.jsx');
|
||||
|
||||
module.exports = Store.createSmartComponent(BrewRenderer, () => {
|
||||
return {
|
||||
brewText : Store.getBrewText(),
|
||||
value : Store.getBrewCode(),
|
||||
style : Store.getBrewStyle(),
|
||||
errors : Store.getErrors()
|
||||
}
|
||||
});
|
||||
@@ -1,70 +1,70 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
const React = require('react');
|
||||
const _ = require('lodash');
|
||||
const cx = require('classnames');
|
||||
|
||||
|
||||
var CodeMirror;
|
||||
let CodeMirror;
|
||||
if(typeof navigator !== 'undefined'){
|
||||
var CodeMirror = require('codemirror');
|
||||
|
||||
CodeMirror = require('codemirror');
|
||||
//Language Modes
|
||||
require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown
|
||||
require('codemirror/mode/javascript/javascript.js');
|
||||
require('codemirror/mode/css/css.js');
|
||||
}
|
||||
|
||||
|
||||
var CodeEditor = React.createClass({
|
||||
const CodeEditor = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
value : '',
|
||||
|
||||
language : '',
|
||||
value : '',
|
||||
wrap : false,
|
||||
onChange : function(){},
|
||||
onCursorActivity : function(){},
|
||||
wrap : true,
|
||||
onChange : ()=>{},
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.codeMirror = CodeMirror(this.refs.editor,{
|
||||
value : this.props.value,
|
||||
lineNumbers: true,
|
||||
lineWrapping : this.props.wrap,
|
||||
mode : this.props.language,
|
||||
});
|
||||
|
||||
this.codeMirror.on('change', this.handleChange);
|
||||
this.codeMirror.on('cursorActivity', this.handleCursorActivity);
|
||||
this.updateSize();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps){
|
||||
if(this.props.language !== nextProps.language){
|
||||
this.buildEditor();
|
||||
}
|
||||
if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
|
||||
this.codeMirror.setValue(nextProps.value);
|
||||
}
|
||||
},
|
||||
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return false;
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.buildEditor();
|
||||
},
|
||||
buildEditor : function(){
|
||||
this.codeMirror = CodeMirror(this.refs.editor,{
|
||||
value : this.props.value,
|
||||
lineNumbers : true,
|
||||
lineWrapping : this.props.wrap,
|
||||
mode : this.props.language,
|
||||
indentWithTabs : true,
|
||||
tabSize : 2
|
||||
});
|
||||
this.codeMirror.on('change', ()=>{
|
||||
this.props.onChange(this.codeMirror.getValue());
|
||||
});
|
||||
this.updateSize();
|
||||
},
|
||||
|
||||
//Externally Used
|
||||
setCursorPosition : function(line, char){
|
||||
setTimeout(()=>{
|
||||
this.codeMirror.focus();
|
||||
this.codeMirror.doc.setCursor(line, char);
|
||||
}, 10);
|
||||
},
|
||||
|
||||
getCursorPosition : function(){
|
||||
return this.codeMirror.getCursor();
|
||||
},
|
||||
updateSize : function(){
|
||||
this.codeMirror.refresh();
|
||||
},
|
||||
|
||||
handleChange : function(editor){
|
||||
this.props.onChange(editor.getValue());
|
||||
},
|
||||
handleCursorActivity : function(){
|
||||
this.props.onCursorActivity(this.codeMirror.doc.getCursor());
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className='codeEditor' ref='editor' />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user