Improved Inputs and NewWordForm, and made inter-component references more prolific.

Made Inputs able to clear themselves, made NewWordForm able to clear itself and not rely on WordForm, added form validation for NewWordForm.
Made Dictionary only display referenced data.
Having trouble getting words to update the list correctly. Editing them works, but adding new words duplicates the first word created when rendering.
This commit is contained in:
Robbie Antenesse 2016-09-22 14:05:49 -06:00
parent 9a90108fe6
commit 9ecfa40ec7
8 changed files with 252 additions and 189 deletions

View File

@ -1,6 +1,5 @@
import React from 'react';
import {Word} from './Word';
import {Button} from './Button';
export class Dictionary extends React.Component {
@ -8,61 +7,20 @@ export class Dictionary extends React.Component {
super(props);
this.state = {
dictionary: this.props.reference,
name: this.props.reference.name,
description: this.props.reference.description,
createdBy: this.props.reference.createdBy,
words: this.props.reference.words,
nextWordId: this.props.reference.nextWordId,
externalID: this.props.reference.externalID,
allowDuplicates: this.props.reference.settings.allowDuplicates,
caseSensitive: this.props.reference.settings.caseSensitive,
partsOfSpeech: this.props.reference.settings.partOfSpeech,
sortByEquivalent: this.props.reference.settings.sortByEquivalent,
isComplete: this.props.reference.settings.isComplete,
isPublic: this.props.reference.settings.isPublic
// name: this.props.reference.name,
// description: this.props.reference.description,
// createdBy: this.props.reference.createdBy,
// nextWordId: this.props.reference.nextWordId,
// externalID: this.props.reference.externalID,
// allowDuplicates: this.props.reference.settings.allowDuplicates,
// caseSensitive: this.props.reference.settings.caseSensitive,
// partsOfSpeech: this.props.reference.settings.partOfSpeech,
// sortByEquivalent: this.props.reference.settings.sortByEquivalent,
// isComplete: this.props.reference.settings.isComplete,
// isPublic: this.props.reference.settings.isPublic
dictionary: this.props.parent.state.details,
settings: this.props.parent.state.settings
}
// this.addTestWord();
}
showWords() {
let words = this.state.words.map((word, index) => {
return <Word key={'dictionaryEntry' + index.toString()}
reference={word}
initialPosition={index} />;
// return <Word key={'dictionaryEntry' + index.toString()}
// name={word.name}
// wordId={word.wordId}
// pronunciation={word.pronunciation}
// partOfSpeech={word.partOfSpeech}
// simpleDefinition={word.simpleDefinition}
// longDefinition={word.longDefinition}
// initialPosition={index} />;
});
return <div>{words}</div>;
}
addTestWord() {
this.setState({
words: this.state.words.concat([{
name: 'word',
pronunciation: 'pronunciation',
partOfSpeech: 'partOfSpeech',
simpleDefinition: 'simpleDefinition',
longDefinition: 'longDefinition',
wordId: 'wordId'
}])
}, () => console.log(this.state.words));
}
changeNameAgain() {
let updateDictionary = this.state.dictionary;
updateDictionary.name = 'something else again'
this.setState({
dictionary: updateDictionary
})
}
render() {
@ -73,27 +31,21 @@ export class Dictionary extends React.Component {
</h1>
<h4 id="dictionaryBy">
{this.state.createdBy}
{this.state.dictionary.createdBy}
</h4>
<div id="incompleteNotice">
Dictionary is complete: {this.state.isComplete.toString()}
Dictionary is complete: {this.state.settings.isComplete.toString()}
</div>
<div id="theDictionary">
{this.showWords()}
{this.props.children}
</div>
<Button
action={() => this.addTestWord()}
label='Add a Test Word' />
<Button
action={() => this.changeNameAgain()}
label='Change Name Again' />
<Button
action={() => {
this.setState({isComplete: !this.state.isComplete})
let tempSettings = this.state.settings;
tempSettings.isComplete = !tempSettings.isComplete;
this.setState({settings: tempSettings})
}}
label='Toggle State' />
</div>

View File

@ -19,13 +19,9 @@ export class Input extends React.Component {
// Bind listeners
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange(event) {
this.setValue(event);
}
// Whenever the input changes we update the value state of this component
setValue(event) {
handleOnChange(event) {
this.setState({
isValid: !(this.props.doValidate && event.currentTarget.value === ''),
value: event.currentTarget.value
@ -42,6 +38,10 @@ export class Input extends React.Component {
}
}
clearField() {
this.setState({value: ''});
}
render() {
return (
<label>

View File

@ -2,29 +2,108 @@ import React from 'react';
import {Input} from './Input';
import {TextArea} from './TextArea';
import {WordForm} from './WordForm';
import {Button} from './Button';
export class NewWordForm extends React.Component {
constructor(props) {
super(props);
this.state = {
errorMessage: '',
updateConflictMessage: ''
};
// Declare local variables as null until mounted.
this.wordField = null;
this.pronunciationField = null;
this.partOfSpeechField = null;
this.simpleDefinitionField = null;
this.longDefinitionField = null;
}
submitWordOnCtrlEnter() {
var keyCode = (event.which ? event.which : event.keyCode);
//Windows and Linux Chrome accept ctrl+enter as keyCode 10.
if (keyCode === keyCodeFor('ctrlEnter') || (keyCode == keyCodeFor('enter') && event.ctrlKey)) {
event.preventDefault();
this.handleSubmit();
}
}
handleSubmit() {
if (this.formIsValid()) {
this.props.addWord({
name: this.wordField.state.value,
pronunciation: this.pronunciationField.state.value,
partOfSpeech: this.partOfSpeechField.state.value,
simpleDefinition: this.simpleDefinitionField.state.value,
longDefinition: this.longDefinitionField.state.value
});
this.clearForm()
}
}
formIsValid() {
let errorMessage = '';
if (this.wordField.state.value.length <= 0) {
errorMessage += 'The word field cannot be blank';
}
if (this.simpleDefinitionField.state.value.length <= 0
&& this.longDefinitionField.state.value.length <= 0) {
errorMessage += ((errorMessage.length > 0) ? ', and there' : 'There')
+ ' must be a value in at least one of the definition fields';
}
if (errorMessage.length > 0) {
errorMessage += '!';
}
this.setState({errorMessage: errorMessage});
return (errorMessage <= 0);
}
clearForm() {
this.wordField.clearField();
this.pronunciationField.clearField();
this.partOfSpeechField.clearField();
this.simpleDefinitionField.clearField();
this.longDefinitionField.clearField();
}
render() {
return (
<WordForm action='new'>
<Input name='Word' />
<form>
<Input name='Word' ref={(inputComponent) => this.wordField = inputComponent} />
<Input name='Pronunciation'
helperLink={{
url: "http://r12a.github.io/pickers/ipa/",
label: "IPA Characters",
hover: "IPA Character Picker located at http://r12a.github.io/pickers/ipa/"
}} />
<Input name='Part of Speech' />
<Input name={<div style={{display: 'inline'}}>Definition/<wbr /><b className="wbr"></b>Equivalent Word(s)</div>} />
}}
ref={(inputComponent) => this.pronunciationField = inputComponent} />
<Input name='Part of Speech' ref={(inputComponent) => this.partOfSpeechField = inputComponent} />
<Input name={<div style={{display: 'inline'}}>Definition/<wbr /><b className="wbr"></b>Equivalent Word(s)</div>}
ref={(inputComponent) => this.simpleDefinitionField = inputComponent} />
<TextArea id='newWordForm'
name={<div style={{display: 'inline'}}>Explanation/<wbr /><b className="wbr"></b>Long Definition</div>} />
</WordForm>
name={<div style={{display: 'inline'}}>Explanation/<wbr /><b className="wbr"></b>Long Definition</div>}
ref={(inputComponent) => this.longDefinitionField = inputComponent} />
<span id="errorMessage">{this.state.errorMessage}</span>
<Button action={() => this.handleSubmit()} label='Add Word' />
<div id="updateConflict">{this.state.updateConflictMessage}</div>
</form>
);
}
}

View File

@ -1,18 +1,17 @@
import React from 'react';
import {Button} from './Button';
export class Word extends React.Component {
constructor(props) {
super(props);
this.state = {
word: this.props.reference,
// name: this.props.name,
// wordId: this.props.wordId,
// pronunciation: this.props.pronunciation || '',
// partOfSpeech: this.props.partOfSpeech || '',
// simpleDefinition: this.props.simpleDefinition || '',
// longDefinition: this.props.longDefinition || '',
sortPosition: this.props.initialPosition
name: this.props.name,
pronunciation: this.props.pronunciation,
partOfSpeech: ((this.props.partOfSpeech.length > 0) ? this.props.partOfSpeech : " "),
simpleDefinition: this.props.simpleDefinition,
longDefinition: this.props.longDefinition
}
}
@ -28,35 +27,63 @@ export class Word extends React.Component {
*/
showPronunciation() {
if (this.state.word.pronunciation !== '') {
return <div className='pronunciation'>{this.state.word.pronunciation}</div>;
if (this.state.pronunciation !== '') {
return <div className='pronunciation'>{this.state.pronunciation}</div>;
}
}
showPartOfSpeech() {
if (this.state.word.partOfSpeech !== '') {
return <div className='part-of-speech'>{this.state.word.partOfSpeech}</div>;
if (this.state.partOfSpeech !== '') {
return <div className='part-of-speech'>{this.state.partOfSpeech}</div>;
}
}
showSimpleDefinition() {
if (this.state.word.simpleDefinition !== '') {
return <div className='simple-definition'>{this.state.word.simpleDefinition}</div>;
if (this.state.simpleDefinition !== '') {
return <div className='simple-definition'>{this.state.simpleDefinition}</div>;
}
}
showLongDefinition() {
if (this.state.word.longDefinition !== '') {
return <div className='long-definition'>{this.state.word.longDefinition}</div>;
if (this.state.longDefinition !== '') {
return <div className='long-definition'>{this.state.longDefinition}</div>;
}
}
showManagementArea() {
if (this.props.isEditing) {
return (
<Button
action={() => this.updateWord()}
label='Save Edits' />
);
}
}
updateWord() {
this.setState({
name: 'this.state.name',
pronunciation: 'this.state.pronunciation',
partOfSpeech: 'this.state.partOfSpeech',
simpleDefinition: 'this.state.simpleDefinition',
longDefinition: 'this.state.longDefinition'
}, () => {
this.props.updateWord(this.props.index, {
name: this.state.name,
pronunciation: this.state.pronunciation,
partOfSpeech: this.state.partOfSpeech,
simpleDefinition: this.state.simpleDefinition,
longDefinition: this.state.longDefinition
});
});
}
render() {
return (
<div id={'entry' + this.state.sortPosition} className='word'>
<a name={'entry' + this.state.word.wordId}></a>
<div id={'entry' + this.props.index} className='word'>
<a name={'entry' + this.props.wordId}></a>
<div className='name'>
{this.state.word.name}
{this.state.name}
</div>
{this.showPronunciation()}
@ -66,7 +93,13 @@ export class Word extends React.Component {
{this.showSimpleDefinition()}
{this.showLongDefinition()}
{this.showManagementArea()}
</div>
);
}
}
Word.defaultProps = {
isEditing: false
}

View File

@ -1,69 +0,0 @@
import React from 'react';
import {Input} from './Input';
import {TextArea} from './TextArea';
import {keyCodeFor} from '../js/helpers';
export class WordForm extends React.Component {
constructor(props) {
super(props);
this.state = {
errorMessage: '',
updateConflictMessage: ''
};
this.isNewWord = (this.props.action == 'new');
}
submitWordOnCtrlEnter() {
var keyCode = (event.which ? event.which : event.keyCode);
//Windows and Linux Chrome accept ctrl+enter as keyCode 10.
if (keyCode === keyCodeFor('ctrlEnter') || (keyCode == keyCodeFor('enter') && event.ctrlKey)) {
event.preventDefault();
this.handleSubmit();
}
}
handleSubmit() {
if (this.validate()) {
}
}
validate() {
return true;
}
confirmArea() {
if (this.isNewWord) {
return <button type="button" onClick={this.handleSubmit}>Add Word</button>;
}
return (
<div id="editWordButtonArea">
<button type="button" onClick={this.handleSubmit}>Edit Word</button>
<button type="button" onClick={this.clearForm}>Cancel</button>
</div>
);
}
clearForm() {
this.props.children.forEach((field) => {
field.state.value = '';
})
}
render() {
return (
<form>
{this.props.children}
<span id="errorMessage">{this.state.errorMessage}</span>
{this.confirmArea}
<div id="updateConflict">{this.state.updateConflictMessage}</div>
</form>
);
}
}

View File

@ -8,39 +8,42 @@ import {Header} from './components/Header';
import {NewWordForm} from './components/NewWordForm';
import {Button} from './components/Button';
import {Dictionary} from './components/Dictionary';
import {Word} from './components/Word';
import {dynamicSort} from './js/helpers';
class Lexiconga extends React.Component {
constructor(props) {
super(props);
this.showConsoleMessages = this.props.showConsoleMessages || false;
this.state = {
scroll: {
x: 0,
y: 0
},
currentDictionary: {
details: {
name: "New",
description: "A new dictionary.",
createdBy: 'Someone',
words: [],
settings: {
allowDuplicates: false,
caseSensitive: false,
partsOfSpeech: "Noun,Adjective,Verb,Adverb,Preposition,Pronoun,Conjunction",
sortByEquivalent: false,
isComplete: false,
isPublic: false
},
nextWordId: 1,
externalID: 0
}
},
words: [],
settings: {
allowDuplicates: false,
caseSensitive: false,
partsOfSpeech: "Noun,Adjective,Verb,Adverb,Preposition,Pronoun,Conjunction",
sortByEquivalent: false,
isComplete: false,
isPublic: false
},
};
this.defaultDictionaryJSON = JSON.stringify(this.state.dictionaryDetails); //Saves a stringifyed default dictionary.
this.previousDictionary = {};
// this.addTestWord();
}
changeDictionaryName() {
@ -54,18 +57,83 @@ class Lexiconga extends React.Component {
})
}
addWord(wordObject) {
let newWord = {
name: wordObject.name || 'errorWord',
pronunciation: wordObject.pronunciation || '',
partOfSpeech: wordObject.partOfSpeech || '',
simpleDefinition: wordObject.simpleDefinition || '',
longDefinition: wordObject.longDefinition || '',
wordId: this.state.details.nextWordId
}
let sortMethod;
if (this.state.settings.sortByEquivalent) {
sortMethod = ['simpleDefinition', 'partOfSpeech'];
} else {
sortMethod = ['name', 'partOfSpeech'];
}
let updatedWords = this.state.words.concat([newWord]);
updatedWords.sort(dynamicSort(sortMethod));
let updatedDetails = this.state.details;
updatedDetails.nextwordid += 1;
this.setState({
words: updatedWords,
details: updatedDetails
}, () => {
if (this.showConsoleMessages) {
console.log('New word ' + newWord.name + ' added successfully');
}
});
}
updateWord(index, wordObject) {
let updatedWords = this.state.words;
updatedWords[index].name = wordObject.name;
updatedWords[index].pronunciation = wordObject.pronunciation;
updatedWords[index].partOfSpeech = wordObject.partOfSpeech;
updatedWords[index].simpledefinition = wordObject.simpledefinition;
updatedWords[index].longDefinition = wordObject.longDefinition;
this.setState({words: updatedWords});
}
showWords() {
let words = this.state.words.map((word, index) => {
return <Word key={'dictionaryEntry' + index.toString()} isEditing={true}
name={word.name}
pronunciation={word.pronunciation}
partOfSpeech={word.partOfSpeech}
simpleDefinition={word.simpleDefinition}
longDefinition={word.longDefinition}
wordId={word.wordId}
index={index}
updateWord={(index, wordObject) => this.updateWord(index, wordObject)} />;
});
return <div>{words}</div>;
}
render() {
return (
<div>
<Header />
<NewWordForm reference={this.state.currentDictionary} />
<NewWordForm addWord={(wordObject) => this.addWord(wordObject)} parent={this} />
<Button
action={() => this.changeDictionaryName()}
label='change name' />
<Dictionary reference={this.state.currentDictionary} />
<div id="incompleteNotice">
Dictionary is complete: {this.state.settings.isComplete.toString()}
</div>
<Dictionary parent={this}>
{this.showWords()}
</Dictionary>
</div>
);
}
}
ReactDOM.render(<Lexiconga />, document.getElementById('site'));
ReactDOM.render(<Lexiconga showConsoleMessages={true} />, document.getElementById('site'));

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
// "what?" version ... http://jsperf.com/diacritics/12
function removeDiacritics(str) {
export function removeDiacritics(str) {
var defaultDiacriticsRemovalap = [
{'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
{'base':'AA','letters':'\uA732'},
@ -115,6 +115,4 @@ function removeDiacritics(str) {
return str.replace(/[^\u0000-\u007E]/g, function(a){
return diacriticsMap[a] || a;
});
}
modules.export = removeDiacritics;
}

View File

@ -1,3 +1,5 @@
import {removeDiacritics} from './dependencies/removeDiacritics';
// function ready(fn) {
// if (document.readyState != 'loading'){
// fn();