Refactored editor component structure
This commit is contained in:
parent
006a1b2e1f
commit
2dd56ed8c5
|
@ -0,0 +1,27 @@
|
|||
import React from 'react'
|
||||
import { ReaderAnnotateButton, ReaderEditButton, EditorToolButton, EditorDeleteToolButton, AnnotatorNewButton, AnnotatorRemoveButton, EditorCancelButton, EditorSubmitButton} from './button'
|
||||
|
||||
export const EditorTitleContentBlock = (props) =>
|
||||
<div id='editor_title_block' className='col-md-12'>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
export const EditorTopBarContentBlock = (props) =>
|
||||
<div id='editor_top_bar_block' className='col-md-12'>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
export const EditorTextContentBlock = (props) =>
|
||||
<div id='editor_text_block' className='col-md-12'>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
export const EditorBottomBarContentBlock = (props) =>
|
||||
<div id='editor_top_bar_block' className='col-md-12'>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
export const EditorAttributeContentBlock = (props) =>
|
||||
<div id='editor_attribute_block' className='col-md-12'>
|
||||
{props.children}
|
||||
</div>
|
|
@ -0,0 +1,49 @@
|
|||
import React from 'react'
|
||||
import { ReaderAnnotateButton, ReaderEditButton, EditorToolButton, EditorDeleteToolButton, AnnotatorNewButton, AnnotatorRemoveButton, EditorCancelButton, EditorSubmitButton} from './button'
|
||||
|
||||
export const EditorReadModeOptions = ({setMode, docType}) =>
|
||||
<div className='row'>
|
||||
{['chapters', 'notes'].indexOf(docType) >= 0 &&
|
||||
<div className='topbar_button col-5'>
|
||||
<ReaderAnnotateButton onClick={()=>setMode('ANNOTATE_MODE')}/>
|
||||
</div>
|
||||
}
|
||||
<div className='topbar_button col-5 ml-auto'>
|
||||
<ReaderEditButton onClick={()=>setMode('EDIT_MODE')} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export const EditorEditModeRichTextOptions = ({editorState, onToolButtonClick, disabled}) =>
|
||||
<div className='row'>
|
||||
<div className='col-5'>
|
||||
<div className='btn-group' role='group'>
|
||||
<EditorToolButton glyph='bold' onClick={()=>onToolButtonClick(editorState, 'BOLD')}/>
|
||||
<EditorToolButton glyph='italic' onClick={()=>onToolButtonClick(editorState, 'ITALIC')}/>
|
||||
<EditorToolButton glyph='underline' onClick={()=>onToolButtonClick(editorState, 'UNDERLINE')}/>
|
||||
<EditorToolButton glyph='header' onClick={()=>onToolButtonClick(editorState, 'header-two')}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-5 offset-2'>
|
||||
<EditorDeleteToolButton disabled={disabled}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export const EditorSubmitOptions = ({cancelEdit, onSubmitClick}) =>
|
||||
<div className='row'>
|
||||
<div className='col-5'>
|
||||
<EditorCancelButton onClick={()=>cancelEdit()}/>
|
||||
</div>
|
||||
<div className='col-5 offset-2'>
|
||||
<EditorSubmitButton onClick={onSubmitClick} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export const EditorAnnotateOptions = ({onNewAnnotationClick, onRemoveAnnotationClick, addDisabled, removeDisabled}) =>
|
||||
<div className='row'>
|
||||
<div className='col-5'>
|
||||
<AnnotatorNewButton onClick={onNewAnnotationClick} disabled={addDisabled}/>
|
||||
</div>
|
||||
<div className='col-5 offset-2'>
|
||||
<AnnotatorRemoveButton onClick={onRemoveAnnotationClick} disabled={removeDisabled} />
|
||||
</div>
|
||||
</div>
|
|
@ -22,7 +22,7 @@ const EditorReadMode = ({
|
|||
<ReadModeTopBar docType={docType} setMode={setMode} />
|
||||
</div>
|
||||
<div id='editor_content' className={'read_mode ' + docType}>
|
||||
<Editor editorState={editorState} readOnly={true}/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Editor } from 'draft-js'
|
||||
|
||||
export const TextEditorReadOnly = ({editorState}) =>
|
||||
<div id='read_only_text_editor' className={'text_editor'}>
|
||||
<Editor editorState={editorState} readOnly={true}/>
|
||||
</div>
|
||||
|
||||
export const TextEditor = ({editorState, handleKeyCommand, onChange}) =>
|
||||
<div id='enabled_text_editor' className={'text_editor'}>
|
||||
<Editor editorState={editorState} handleKeyCommand={handleKeyCommand} onChange={onChange}/>
|
||||
</div>
|
||||
|
||||
export const TextEditorAnnotateOnly = ({editorState, handleKeyCommand, onChange}) =>
|
||||
<div id='enabled_text_editor' className={'text_editor'}>
|
||||
<Editor editorState={editorState} handleKeyCommand={handleKeyCommand} onChange={onChange}/>
|
||||
</div>
|
|
@ -0,0 +1,91 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { TextEditorAnnotateOnly } from '../components/textEditor'
|
||||
import { EditorTitleContentBlock, EditorTopBarContentBlock, EditorTextContentBlock, EditorBottomBarContentBlock } from '../components/editorContentBlock'
|
||||
import { EditorEditModeRichTextOptions, EditorSubmitOptions, EditorAnnotateOptions } from '../components/editorOptionBlock'
|
||||
import actions from '../actions'
|
||||
import DocumentTitle from '../components/documentTitle'
|
||||
import TagColorPicker from '../components/tagColorPicker'
|
||||
import LoadingSpinner from '../components/loadingSpinner'
|
||||
|
||||
const EditorAnnotateMode = ({
|
||||
currentDocument,
|
||||
editorState,
|
||||
docType,
|
||||
toggles,
|
||||
inputs,
|
||||
onChangeEditorState,
|
||||
onNewAnnotationClick,
|
||||
annotateKeyBindings,
|
||||
onRemoveAnnotationClick,
|
||||
cancelEdit,
|
||||
onSubmitClick,
|
||||
}) =>
|
||||
<div id='editor_edit_mode' className='editor_wrapper'>
|
||||
<EditorTitleContentBlock>
|
||||
<DocumentTitle
|
||||
docType={docType}
|
||||
currentDocument={currentDocument}
|
||||
/>
|
||||
</EditorTitleContentBlock>
|
||||
<EditorTopBarContentBlock>
|
||||
<EditorAnnotateOptions
|
||||
onNewAnnotationClick={()=>onNewAnnotationClick(editorState.getSelection())}
|
||||
onRemoveAnnotationClick={()=>onRemoveAnnotationClick(editorState)}
|
||||
addDisabled={editorState.getSelection().isCollapsed() ? true : false}
|
||||
removeDisabled={(editorState.getSelection().isCollapsed() ) ? true : false}
|
||||
/>
|
||||
</EditorTopBarContentBlock>
|
||||
<EditorTextContentBlock>
|
||||
<TextEditorAnnotateOnly
|
||||
editorState={editorState}
|
||||
onChange={onChangeEditorState}
|
||||
keyBindingFn={annotateKeyBindings}
|
||||
/>
|
||||
</EditorTextContentBlock>
|
||||
<EditorBottomBarContentBlock>
|
||||
<EditorSubmitOptions
|
||||
cancelEdit={cancelEdit}
|
||||
onSubmitClick={()=>onSubmitClick(currentDocument, editorState, inputs, docType)}
|
||||
/>
|
||||
</EditorBottomBarContentBlock>
|
||||
</div>
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
currentDocument: state.currentDocument,
|
||||
docType: state.docType,
|
||||
editorState: state.editorState,
|
||||
toggles: state.toggles,
|
||||
inputs: state.inputs,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onChangeEditorState: editorState => {
|
||||
dispatch(actions.updateEditorState(editorState))
|
||||
},
|
||||
annotateKeyBindings: () => {
|
||||
// Prevents editor input in Annotation Mode
|
||||
return 'handled'
|
||||
},
|
||||
cancelEdit: () => {
|
||||
dispatch(actions.cancelEdit())
|
||||
},
|
||||
onNewAnnotationClick: (selectionState) => {
|
||||
dispatch(actions.addAnnotation(selectionState))
|
||||
},
|
||||
onRemoveAnnotationClick: (editorState) => {
|
||||
dispatch(actions.removeAnnotation(editorState))
|
||||
},
|
||||
onSubmitClick: (currentDocument, editorState, inputs, docType) => {
|
||||
dispatch(actions.submitDocumentEdit(currentDocument, editorState, inputs, docType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EditorAnnotateModeContainer = connect(mapStateToProps, mapDispatchToProps)(EditorAnnotateMode)
|
||||
|
||||
export default EditorAnnotateModeContainer
|
|
@ -3,151 +3,33 @@ import PropTypes from 'prop-types'
|
|||
import { connect } from 'react-redux'
|
||||
|
||||
import actions from '../actions'
|
||||
import EditorReadMode from '../components/editorReadMode'
|
||||
import EditorAnnotateMode from '../components/editorAnnotateMode'
|
||||
import EditorEditMode from '../components/editorEditMode'
|
||||
import EditorReadModeContainer from '../containers/editorReadModeContainer'
|
||||
import EditorAnnotateModeContainer from '../containers/editorAnnotateModeContainer'
|
||||
import EditorEditModeContainer from '../containers/editorEditModeContainer'
|
||||
|
||||
const EditorContent = ({
|
||||
// State
|
||||
currentDocument,
|
||||
editorState,
|
||||
docType,
|
||||
mode,
|
||||
toggles,
|
||||
inputs,
|
||||
userErrors,
|
||||
//Dispatch
|
||||
handleKeyCommand,
|
||||
onChangeEditorState,
|
||||
onToolButtonClick,
|
||||
setMode,
|
||||
cancelEdit,
|
||||
onSubmitClick,
|
||||
onColorSwatchClick,
|
||||
onDocumentTitleChange,
|
||||
onColorPickerInputChange,
|
||||
onNewAnnotationClick,
|
||||
annotateKeyBindings,
|
||||
onRemoveAnnotationClick,
|
||||
}) =>
|
||||
const EditorContent = ({mode}) =>
|
||||
<div id='editor_container'>
|
||||
{mode === 'READ_MODE' &&
|
||||
<EditorReadMode
|
||||
currentDocument={currentDocument}
|
||||
editorState={editorState}
|
||||
docType={docType}
|
||||
toggles={toggles}
|
||||
setMode={setMode}
|
||||
/>
|
||||
<EditorReadModeContainer />
|
||||
}
|
||||
{mode === 'ANNOTATE_MODE' &&
|
||||
<EditorAnnotateMode
|
||||
currentDocument={currentDocument}
|
||||
editorState={editorState}
|
||||
docType={docType}
|
||||
toggles={toggles}
|
||||
handleKeyCommand={handleKeyCommand}
|
||||
onNewAnnotationClick={()=>onNewAnnotationClick(editorState.getSelection())}
|
||||
onRemoveAnnotationClick={()=>onRemoveAnnotationClick(editorState)}
|
||||
annotateKeyBindings={annotateKeyBindings}
|
||||
onChangeEditorState={onChangeEditorState}
|
||||
onToolButtonClick={onToolButtonClick}
|
||||
setMode={setMode}
|
||||
cancelEdit={cancelEdit}
|
||||
onSubmitClick={()=>onSubmitClick(currentDocument, editorState, inputs, docType)}
|
||||
/>
|
||||
<EditorAnnotateModeContainer />
|
||||
}
|
||||
{mode === 'EDIT_MODE' &&
|
||||
<EditorEditMode
|
||||
currentDocument={currentDocument}
|
||||
editorState={editorState}
|
||||
docType={docType}
|
||||
toggles={toggles}
|
||||
onChangeEditorState={onChangeEditorState}
|
||||
cancelEdit={cancelEdit}
|
||||
onSubmitClick={()=>onSubmitClick(currentDocument, editorState, inputs, docType)}
|
||||
inputs={inputs}
|
||||
onColorSwatchClick={onColorSwatchClick}
|
||||
onDocumentTitleChange={onDocumentTitleChange}
|
||||
onColorPickerInputChange={onColorPickerInputChange}
|
||||
userErrors={userErrors}
|
||||
/>
|
||||
<EditorEditModeContainer />
|
||||
}
|
||||
</div>
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
currentDocument: state.currentDocument,
|
||||
mode: state.mode,
|
||||
docType: state.docType,
|
||||
editorState: state.editorState,
|
||||
inputs: state.inputs,
|
||||
toggles: state.toggles,
|
||||
userErrors: state.userErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onChangeEditorState: editorState => {
|
||||
dispatch(actions.updateEditorState(editorState))
|
||||
},
|
||||
onDocumentTitleChange: input => {
|
||||
dispatch(actions.updateDocumentTitleInput(input))
|
||||
},
|
||||
onColorPickerInputChange: input => {
|
||||
dispatch(actions.updateColorPickerInput(input))
|
||||
},
|
||||
handleKeyCommand: (command, editorState) => {
|
||||
dispatch(actions.handleEditorKeyCommand(editorState, command))
|
||||
},
|
||||
annotateKeyBindings: () => {
|
||||
// Prevents editor input in Annotation Mode
|
||||
return 'handled'
|
||||
},
|
||||
setMode: (mode) => {
|
||||
dispatch(actions.setMode(mode))
|
||||
},
|
||||
cancelEdit: () => {
|
||||
dispatch(actions.cancelEdit())
|
||||
},
|
||||
onColorSwatchClick: (color) => {
|
||||
dispatch(actions.selectColorSwatch(color))
|
||||
},
|
||||
onNewAnnotationClick: (selectionState) => {
|
||||
dispatch(actions.addAnnotation(selectionState))
|
||||
},
|
||||
onRemoveAnnotationClick: (editorState) => {
|
||||
dispatch(actions.removeAnnotation(editorState))
|
||||
},
|
||||
onToolButtonClick: (editorState, style) => {
|
||||
dispatch(actions.applyInlineStyles(editorState, style))
|
||||
},
|
||||
onSubmitClick: (currentDocument, editorState, inputs, docType) => {
|
||||
dispatch(actions.submitDocumentEdit(currentDocument, editorState, inputs, docType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorContent.propTypes = {
|
||||
currentDocument: PropTypes.object,
|
||||
editorState: PropTypes.object,
|
||||
inputs: PropTypes.object,
|
||||
docType: PropTypes.string,
|
||||
mode: PropTypes.string,
|
||||
toggles: PropTypes.object,
|
||||
handleKeyCommand: PropTypes.func,
|
||||
onChangeEditorState: PropTypes.func,
|
||||
onToolButtonClick: PropTypes.func,
|
||||
setMode: PropTypes.func,
|
||||
cancelEdit: PropTypes.func,
|
||||
onSubmitClick: PropTypes.func,
|
||||
onDocumentTitleChange: PropTypes.func,
|
||||
onNewAnnotationClick: PropTypes.func,
|
||||
annotateKeyBindings: PropTypes.func,
|
||||
onRemoveAnnotationClick: PropTypes.func,
|
||||
mode: PropTypes.string
|
||||
}
|
||||
|
||||
const EditorContentContainer = connect(mapStateToProps, mapDispatchToProps)(EditorContent)
|
||||
const EditorContentContainer = connect(mapStateToProps)(EditorContent)
|
||||
|
||||
export default EditorContentContainer
|
|
@ -0,0 +1,113 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { TextEditor } from '../components/textEditor'
|
||||
import { EditorTitleContentBlock, EditorTopBarContentBlock, EditorTextContentBlock, EditorBottomBarContentBlock, EditorAttributeContentBlock } from '../components/editorContentBlock'
|
||||
import { EditorEditModeRichTextOptions, EditorSubmitOptions } from '../components/editorOptionBlock'
|
||||
import actions from '../actions'
|
||||
import DocumentTitle from '../components/documentTitle'
|
||||
import TagColorPicker from '../components/tagColorPicker'
|
||||
import LoadingSpinner from '../components/loadingSpinner'
|
||||
|
||||
const EditorEditMode = ({
|
||||
currentDocument,
|
||||
docType,
|
||||
editorState,
|
||||
inputs,
|
||||
userErrors,
|
||||
handleKeyCommand,
|
||||
onChangeEditorState,
|
||||
onDocumentTitleChange,
|
||||
onColorPickerInputChange,
|
||||
onColorSwatchClick,
|
||||
cancelEdit,
|
||||
onSubmitClick,
|
||||
onToolButtonClick,
|
||||
}) =>
|
||||
<div id='editor_edit_mode' className='editor_wrapper'>
|
||||
<EditorTitleContentBlock>
|
||||
<input
|
||||
type='text'
|
||||
value={inputs.documentTitle}
|
||||
placeholder='Document Title'
|
||||
onChange={onDocumentTitleChange}
|
||||
/>
|
||||
</EditorTitleContentBlock>
|
||||
<EditorTopBarContentBlock>
|
||||
<EditorEditModeRichTextOptions
|
||||
editorState={editorState}
|
||||
onToolButtonClick={onToolButtonClick}
|
||||
disabled={!currentDocument.id ? true : false}
|
||||
/>
|
||||
</EditorTopBarContentBlock>
|
||||
<EditorTextContentBlock>
|
||||
<TextEditor
|
||||
editorState={editorState}
|
||||
handleKeyCommand={handleKeyCommand}
|
||||
onChange={onChangeEditorState}
|
||||
/>
|
||||
</EditorTextContentBlock>
|
||||
<EditorAttributeContentBlock>
|
||||
{docType === 'tags' &&
|
||||
<TagColorPicker
|
||||
input={inputs.colorPicker}
|
||||
onChange={onColorPickerInputChange}
|
||||
onColorSwatchClick={onColorSwatchClick}
|
||||
/>
|
||||
}
|
||||
</EditorAttributeContentBlock>
|
||||
<EditorBottomBarContentBlock>
|
||||
<EditorSubmitOptions
|
||||
cancelEdit={cancelEdit}
|
||||
onSubmitClick={()=>onSubmitClick(currentDocument, editorState, inputs, docType)}
|
||||
/>
|
||||
</EditorBottomBarContentBlock>
|
||||
<div id='user_errors'>
|
||||
{userErrors.map(error =>
|
||||
<div key={error} className='user_error_message'>{error}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
currentDocument: state.currentDocument,
|
||||
docType: state.docType,
|
||||
editorState: state.editorState,
|
||||
inputs: state.inputs,
|
||||
userErrors: state.userErrors,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onChangeEditorState: editorState => {
|
||||
dispatch(actions.updateEditorState(editorState))
|
||||
},
|
||||
onDocumentTitleChange: input => {
|
||||
dispatch(actions.updateDocumentTitleInput(input))
|
||||
},
|
||||
onColorPickerInputChange: input => {
|
||||
dispatch(actions.updateColorPickerInput(input))
|
||||
},
|
||||
handleKeyCommand: (command, editorState) => {
|
||||
dispatch(actions.handleEditorKeyCommand(editorState, command))
|
||||
},
|
||||
cancelEdit: () => {
|
||||
dispatch(actions.cancelEdit())
|
||||
},
|
||||
onColorSwatchClick: (color) => {
|
||||
dispatch(actions.selectColorSwatch(color))
|
||||
},
|
||||
onToolButtonClick: (editorState, style) => {
|
||||
dispatch(actions.applyInlineStyles(editorState, style))
|
||||
},
|
||||
onSubmitClick: (currentDocument, editorState, inputs, docType) => {
|
||||
dispatch(actions.submitDocumentEdit(currentDocument, editorState, inputs, docType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EditorEditModeContainer = connect(mapStateToProps, mapDispatchToProps)(EditorEditMode)
|
||||
|
||||
export default EditorEditModeContainer
|
|
@ -0,0 +1,59 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Editor } from 'draft-js'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { TextEditorReadOnly } from '../components/textEditor'
|
||||
import { EditorTitleContentBlock, EditorTopBarContentBlock, EditorTextContentBlock } from '../components/editorContentBlock'
|
||||
import { EditorReadModeOptions } from '../components/editorOptionBlock'
|
||||
import actions from '../actions'
|
||||
import DocumentTitle from '../components/documentTitle'
|
||||
|
||||
const EditorReadMode = ({
|
||||
currentDocument,
|
||||
editorState,
|
||||
docType,
|
||||
toggles,
|
||||
setMode
|
||||
}) =>
|
||||
<div id='editor_read_mode' className='editor_wrapper'>
|
||||
<EditorTitleContentBlock>
|
||||
<DocumentTitle
|
||||
docType={docType}
|
||||
currentDocument={currentDocument}
|
||||
/>
|
||||
</EditorTitleContentBlock>
|
||||
<EditorTopBarContentBlock>
|
||||
<EditorReadModeOptions
|
||||
setMode={setMode}
|
||||
docType={docType}
|
||||
/>
|
||||
</EditorTopBarContentBlock>
|
||||
<EditorTextContentBlock>
|
||||
<TextEditorReadOnly
|
||||
editorState={editorState}
|
||||
/>
|
||||
</EditorTextContentBlock>
|
||||
</div>
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
currentDocument: state.currentDocument,
|
||||
editorState: state.editorState,
|
||||
docType: state.docType,
|
||||
toggles: state.toggles,
|
||||
mode: state.mode,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setMode: (mode) => {
|
||||
dispatch(actions.setMode(mode))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const EditorReadModeContainer = connect(mapStateToProps, mapDispatchToProps)(EditorReadMode)
|
||||
|
||||
export default EditorReadModeContainer
|
|
@ -1,6 +1,24 @@
|
|||
@import "variables";
|
||||
@import "mixin";
|
||||
|
||||
.text_editor {
|
||||
max-height: 72vh;
|
||||
overflow-y: auto;
|
||||
background-color: rgba(256,256,256,.8);
|
||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||
margin: 1vh 0;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 5px;
|
||||
padding: 2% 5%;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// PRE-FACTOR
|
||||
|
||||
|
||||
#editor_container {
|
||||
height: 82vh;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue