Start creating EditDictionaryModal and related pieces

Add Updater for saving new values.
Add EditDictionaryForm and EditLinguisticsForm.
Add helpful Array and Object functions to Helper.
This commit is contained in:
Robbie Antenesse 2017-08-16 16:53:55 -06:00
parent 24301cc7e6
commit c8a7c1436f
8 changed files with 381 additions and 13 deletions

View File

@ -15,6 +15,38 @@ class Helper {
characterIsUppercase (character) {
return character === character.toUpperCase();
}
arraysAreEqual (array1, array2) {
// if the other array2 is a falsy value, return
if (!array1 || !array2)
return false;
// compare lengths - can save a lot of time
if (array1.length != array2.length)
return false;
for (var i = 0, l=array1.length; i < l; i++) {
// Check if we have nested arrays
if (array1[i] instanceof Array && array2[i] instanceof Array) {
// recurse into the nested arrays
if (!array1[i].equals(array2[i]))
return false;
}
else if (array1[i] != array2[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
objectIsEmpty (obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
}
export default new Helper;

58
src/Updater.js Normal file
View File

@ -0,0 +1,58 @@
import helper from './Helper';
export class Updater {
constructor (appWithDictionaryState, dictionary) {
this.app = appWithDictionaryState;
this.dictionary = dictionary;
}
setDictionaryName (newName) {
this.app.setState({
name: newName,
}, () => {
this.dictionary.name = newName;
});
}
setDictionarySpecification (newSpecification) {
this.app.setState({
specification: newSpecification,
}, () => {
this.dictionary.specification = newSpecification;
});
}
updateDictionaryDetails (dicitonaryDetails = {}) {
return new Promise((resolve, reject) => {
const updatedDetails = {};
if (dicitonaryDetails.name) {
updatedDetails['name'] = dicitonaryDetails.name;
this.dictionary.name = dicitonaryDetails.name;
}
if (dicitonaryDetails.specification) {
updatedDetails['specification'] = dicitonaryDetails.specification;
this.dicitonary.specification = dicitonaryDetails.specification;
}
if (dicitonaryDetails.description) {
updatedDetails['description'] = dicitonaryDetails.description;
this.dictionary.description = dicitonaryDetails.description;
}
if (dicitonaryDetails.partsOfSpeech) {
updatedDetails['partsOfSpeech'] = dicitonaryDetails.partsOfSpeech;
this.dictionary.partsOfSpeech = dicitonaryDetails.partsOfSpeech;
}
if (helper.objectIsEmpty(updatedDetails)) {
reject('No dictionary details have changed.');
} else {
this.app.setState(updatedDetails, () => {
resolve();
});
}
});
}
}

View File

@ -7,7 +7,7 @@ import { WordForm } from './management/WordForm';
import { DictionaryDetails } from './display/DictionaryDetails';
import { WordsList } from './display/WordsList';
export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, lastRender }) => {
export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, updater, lastRender }) => {
return (
<section className='section'>
<div className='container'>
@ -22,9 +22,11 @@ export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, las
<RightColumn>
<DictionaryDetails
updater={ updater }
name={ dictionaryInfo.name }
specification={ dictionaryInfo.specification }
description={ dictionaryInfo.description }
partsOfSpeech={ dictionaryInfo.partsOfSpeech }
details={{
custom: [
{

View File

@ -0,0 +1,63 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import dictionary from '../../../../managers/DictionaryData';
export const EditDictionaryForm = ({
editDictionaryModal,
name,
specification,
description,
}) => {
return (
<div className='form'>
<div className='field'>
<label className='label'>Name</label>
<div className='control'>
<input className='input' type='text'
placeholder={ `${ specification || 'Dictionary' } Name` }
value={ name }
onInput={ (event) => {
editDictionaryModal.setState({
name: event.target.value,
hasChanged: event.target.value != editDictionaryModal.props.name,
});
}}
/>
</div>
</div>
<div className='field'>
<label className='label'>Specification</label>
<div className='control'>
<input className='input' type='text'
placeholder='Dictionary'
value={ specification }
onInput={ (event) => {
editDictionaryModal.setState({
specification: event.target.value,
hasChanged: event.target.value != editDictionaryModal.props.specification,
});
}}
/>
</div>
</div>
<div className='field'>
<label className='label' htmlFor='dictionaryDescription'>Description</label>
<div className='control'>
<textarea className='textarea' id='dictionaryDescription'
placeholder={ `A description of your ${ specification }` }
value={ description }
onInput={ (event) => {
editDictionaryModal.setState({
description: event.target.value,
hasChanged: event.target.value != editDictionaryModal.props.description,
});
}}
/>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,29 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import dictionary from '../../../../managers/DictionaryData';
export const EditLinguisticsForm = ({
editDictionaryModal,
partsOfSpeech,
}) => {
return (
<div className='form'>
<div className='field'>
<label className='label' htmlFor='dictionaryDescription'>Parts of Speech</label>
<div className='control'>
<textarea className='textarea' id='partsOfSpeech'
placeholder={ `Put each part of speech on a separate line` }
value={ partsOfSpeech }
onInput={ (event) => {
editDictionaryModal.setState({
partsOfSpeech: event.target.value,
hasChanged: event.target.value != editDictionaryModal.props.partsOfSpeech.join('\n'),
});
}}
/>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,170 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import marked from 'marked';
import helper from '../../../../Helper';
import { Modal } from '../../../structure/Modal';
import { EditDictionaryForm } from './EditDictionaryForm';
import { EditLinguisticsForm } from './EditLinguisticsForm';
const DISPLAY = {
DETAILS: 1,
LINGUISTICS: 2,
SETTINGS: 3,
}
export class EditDictionaryModal extends Component {
constructor (props) {
super(props);
this.state = {
currentDisplay: DISPLAY.DETAILS,
name: props.name,
specification: props.specification,
description: props.description,
partsOfSpeech: props.partsOfSpeech.join('\n'),
hasChanged: false,
}
}
hasChanged () {
return (
this.state.name != this.props.name
|| this.state.specification != this.props.specification
|| this.state.description != this.props.description
|| this.state.partsOfSpeech != this.props.partsOfSpeech.join('\n')
);
}
toggleDisplay (display) {
this.setState({
currentDisplay: display,
});
}
displaySection () {
let displayJSX;
switch(this.state.currentDisplay) {
case DISPLAY.DETAILS : {
displayJSX = (
<EditDictionaryForm
editDictionaryModal={ this }
name={ this.state.name }
specification={ this.state.specification }
description={ this.state.description }
/>
);
break;
}
case DISPLAY.LINGUISTICS : {
displayJSX = (
<EditLinguisticsForm
editDictionaryModal={ this }
partsOfSpeech={ this.state.partsOfSpeech }
/>
);
break;
}
case DISPLAY.SETTINGS : {
displayJSX = (
<div className='content'>
<p>Settings!</p>
</div>
);
break;
}
}
return (
<div className='box'>
{ displayJSX }
</div>
);
}
save () {
const updatedDetails = {};
if (this.state.name !== this.props.name) {
updatedDetails['name'] = this.state.name;
}
if (this.state.specification !== this.props.specification) {
updatedDetails['specification'] = this.state.specification;
}
if (this.state.description !== this.props.description) {
updatedDetails['description'] = this.state.description;
}
if (this.state.partsOfSpeech !== this.props.partsOfSpeech.join('\n')) {
updatedDetails['partsOfSpeech'] = this.state.partsOfSpeech.split('\n')
.filter((value) => { return value !== '' })
.map((value) => { return value.trim() });
}
console.log(updatedDetails);
this.props.updater.updateDictionaryDetails(updatedDetails)
.then(() => {
this.setState({ hasChanged: false });
})
.catch(errorMessage => {
console.error(errorMessage);
});
}
render () {
const { currentDisplay, hasChanged } = this.state;
return (
<Modal title={ `Edit ${ this.props.specification }` }
buttonText={ `Edit ${ this.props.specification }` }
footerAlign='right'
footerContent={
(
<div>
<button className='button is-success'
disabled={ !hasChanged }
onClick={ this.save.bind(this) }
>
Save
</button>
</div>
)
}
>
<div className='tabs'>
<ul>
<li className={ (currentDisplay === DISPLAY.DETAILS) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.DETAILS) }>
Details
</a>
</li>
<li className={ (currentDisplay === DISPLAY.LINGUISTICS) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.LINGUISTICS) }>
Linguistics
</a>
</li>
<li className={ (currentDisplay === DISPLAY.SETTINGS) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.SETTINGS) }>
Settings
</a>
</li>
</ul>
</div>
{ this.displaySection() }
</Modal>
);
}
}

View File

@ -2,6 +2,8 @@ import Inferno from 'inferno';
import Component from 'inferno-component';
import marked from 'marked';
import { EditDictionaryModal } from './EditDictionaryModal';
const DISPLAY = {
NONE: false,
DESCRIPTION: 1,
@ -132,6 +134,8 @@ export class DictionaryDetails extends Component {
}
render () {
const { currentDisplay } = this.state;
return (
<div className='box'>
@ -146,30 +150,33 @@ export class DictionaryDetails extends Component {
<div className='level-right'>
<div className='level-item'>
<div className='field'>
<p className='control'>
<a className='button'>
Edit Dictionary
</a>
</p>
</div>
<EditDictionaryModal
updater={ this.props.updater }
name={ this.props.name }
specification={ this.props.specification }
description={ this.props.description }
partsOfSpeech={ this.props.partsOfSpeech }
details={ this.props.details }
/>
</div>
</div>
</div>
<div className='tabs is-toggle'>
<ul>
<li className={ (this.state.currentDisplay === DISPLAY.DESCRIPTION) ? 'is-active' : null }>
<li className={ (currentDisplay === DISPLAY.DESCRIPTION) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.DESCRIPTION) }>
<span>Description</span>
</a>
</li>
<li className={ (this.state.currentDisplay === DISPLAY.DETAILS) ? 'is-active' : null }>
<li className={ (currentDisplay === DISPLAY.DETAILS) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.DETAILS) }>
<span>Details</span>
</a>
</li>
<li className={ (this.state.currentDisplay === DISPLAY.STATS) ? 'is-active' : null }>
<li className={ (currentDisplay === DISPLAY.STATS) ? 'is-active' : null }>
<a onClick={ this.toggleDisplay.bind(this, DISPLAY.STATS) }>
<span>Stats</span>
</a>

View File

@ -6,6 +6,8 @@ import Component from 'inferno-component';
import dictionary from './managers/DictionaryData';
import { Updater } from './Updater';
if (process.env.NODE_ENV !== 'production') {
require('inferno-devtools');
}
@ -26,6 +28,8 @@ class App extends Component {
displayedWords: [],
searchConfig: null,
}
this.updater = new Updater(this, dictionary);
}
get dictionaryInfo () {
@ -68,12 +72,15 @@ class App extends Component {
<div>
<Header
partsOfSpeech={ this.state.partsOfSpeech }
search={ (searchConfig) => this.search(searchConfig) } />
search={ (searchConfig) => this.search(searchConfig) }
/>
<MainDisplay
dictionaryInfo={ this.dictionaryInfo }
wordsToDisplay={ this.state.displayedWords }
updateDisplay={ this.updateDisplayedWords.bind(this) } />
updateDisplay={ this.updateDisplayedWords.bind(this) }
updater={ this.updater }
/>
<Footer />
</div>