2016-11-03 19:39:47 +01:00
|
|
|
// Import the HTML file and sass for Webpack to handle.
|
2016-09-21 22:40:25 +02:00
|
|
|
import './index.html';
|
2016-09-22 02:18:54 +02:00
|
|
|
import './sass/main.scss';
|
2016-09-21 22:40:25 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Import React for the React.Component class and ReactDOM for rendering.
|
2016-09-21 22:40:25 +02:00
|
|
|
import React from 'react';
|
|
|
|
import ReactDOM from 'react-dom';
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Import the necessary components.
|
2016-09-22 02:18:54 +02:00
|
|
|
import {Header} from './components/Header';
|
2016-09-27 23:12:48 +02:00
|
|
|
import {Footer} from './components/Footer';
|
2016-09-24 15:59:06 +02:00
|
|
|
import {WordForm} from './components/WordForm';
|
2016-09-22 16:25:49 +02:00
|
|
|
import {Button} from './components/Button';
|
2016-09-30 04:26:16 +02:00
|
|
|
import {InfoDisplay} from './components/InfoDisplay';
|
2016-09-28 01:10:03 +02:00
|
|
|
import {EditDictionaryForm} from './components/EditDictionaryForm';
|
2016-09-22 02:18:54 +02:00
|
|
|
import {Dictionary} from './components/Dictionary';
|
2016-09-22 22:05:49 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Import the helper functions needed for this file.
|
2016-09-22 22:05:49 +02:00
|
|
|
import {dynamicSort} from './js/helpers';
|
2016-09-21 22:40:25 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Declare the values of the default empty dictionary.
|
|
|
|
const defaultDictionaryName = 'New'
|
|
|
|
, defaultListTypeName = 'Dictionary'
|
|
|
|
, defaultDictionaryDescription = 'A new dictionary.'
|
|
|
|
, defaultDictionaryCreatedBy = 'Someone'
|
|
|
|
, defaultDictionaryPartsOfSpeech = 'Noun,Adjective,Verb,Adverb,Preposition,Pronoun,Conjunction'
|
|
|
|
;
|
2016-09-24 17:59:19 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Create the Lexiconga component just for rendering the whole site.
|
2016-09-21 22:40:25 +02:00
|
|
|
class Lexiconga extends React.Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2016-09-22 02:18:54 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// This could probably be a global constant instead.
|
2016-09-22 22:05:49 +02:00
|
|
|
this.showConsoleMessages = this.props.showConsoleMessages || false;
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Put the dictionary details, settings, and words into the state so modifications will affect display.
|
2016-09-22 02:18:54 +02:00
|
|
|
this.state = {
|
|
|
|
scroll: {
|
2016-11-03 19:39:47 +01:00
|
|
|
x: 0
|
|
|
|
, y: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
, details: {
|
|
|
|
name: defaultDictionaryName
|
|
|
|
, listTypeName: defaultListTypeName
|
|
|
|
, description: defaultDictionaryDescription
|
|
|
|
, createdBy: defaultDictionaryCreatedBy
|
|
|
|
, nextWordId: 1
|
|
|
|
, externalID: 0
|
|
|
|
}
|
|
|
|
, words: []
|
|
|
|
, settings: {
|
|
|
|
allowDuplicates: false
|
|
|
|
, caseSensitive: false
|
|
|
|
, partsOfSpeech: defaultDictionaryPartsOfSpeech
|
|
|
|
, sortByEquivalent: false
|
|
|
|
, isComplete: false
|
|
|
|
, isPublic: false
|
2016-09-23 02:08:14 +02:00
|
|
|
}
|
2016-09-22 15:42:07 +02:00
|
|
|
};
|
2016-09-22 02:18:54 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
//Saves a stringifyed default dictionary. Actually does nothing because this value doesn't exist.
|
|
|
|
this.defaultDictionaryJSON = JSON.stringify(this.state.dictionaryDetails);
|
2016-09-22 02:18:54 +02:00
|
|
|
this.previousDictionary = {};
|
2016-09-21 22:40:25 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Receive an object containing changes to the dictionary details and settings, apply them to the state,
|
|
|
|
// and save the local dictionary after the state is updated.
|
2016-09-28 01:10:03 +02:00
|
|
|
saveChanges(changesObject) {
|
|
|
|
let updatedDetails = this.state.details;
|
|
|
|
let updatedSettings = this.state.settings;
|
|
|
|
|
|
|
|
updatedDetails.name = changesObject.name;
|
2016-09-30 06:59:25 +02:00
|
|
|
updatedDetails.listTypeName = changesObject.listTypeName;
|
2016-09-28 01:10:03 +02:00
|
|
|
updatedDetails.description = changesObject.description;
|
|
|
|
|
|
|
|
updatedSettings.partsOfSpeech = changesObject.partsOfSpeech;
|
|
|
|
updatedSettings.allowDuplicates = changesObject.allowDuplicates;
|
|
|
|
updatedSettings.caseSensitive = changesObject.caseSensitive;
|
|
|
|
updatedSettings.sortByEquivalent = changesObject.sortByEquivalent;
|
|
|
|
updatedSettings.isComplete = changesObject.isComplete;
|
|
|
|
updatedSettings.isPublic = changesObject.isPublic;
|
|
|
|
|
2016-09-22 16:25:49 +02:00
|
|
|
this.setState({
|
2016-09-28 01:10:03 +02:00
|
|
|
details: updatedDetails,
|
|
|
|
settings: updatedSettings
|
|
|
|
}, () => {
|
|
|
|
this.saveLocalDictionary();
|
|
|
|
});
|
2016-09-22 16:25:49 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Sort the given array of word objects in the state according to the sortByEquivalent setting.
|
|
|
|
sortWords(wordsArray) {
|
2016-09-23 02:08:14 +02:00
|
|
|
let sortMethod;
|
|
|
|
if (this.state.settings.sortByEquivalent) {
|
|
|
|
sortMethod = ['simpleDefinition', 'partOfSpeech'];
|
|
|
|
} else {
|
|
|
|
sortMethod = ['name', 'partOfSpeech'];
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
return wordsArray.sort(dynamicSort(sortMethod));
|
2016-09-23 02:08:14 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Receive a word object, process it, and update the words state array with the new word.
|
2016-09-22 22:05:49 +02:00
|
|
|
addWord(wordObject) {
|
|
|
|
let newWord = {
|
2016-11-03 19:39:47 +01:00
|
|
|
name: wordObject.name || 'errorWord'
|
|
|
|
, pronunciation: wordObject.pronunciation || ''
|
|
|
|
, partOfSpeech: wordObject.partOfSpeech || ''
|
|
|
|
, simpleDefinition: wordObject.simpleDefinition || ''
|
|
|
|
, longDefinition: wordObject.longDefinition || ''
|
|
|
|
, wordId: this.state.details.nextWordId
|
2016-09-22 22:05:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let updatedWords = this.state.words.concat([newWord]);
|
2016-09-23 02:08:14 +02:00
|
|
|
updatedWords = this.sortWords(updatedWords);
|
2016-09-22 22:05:49 +02:00
|
|
|
|
|
|
|
let updatedDetails = this.state.details;
|
2016-09-24 16:58:09 +02:00
|
|
|
updatedDetails.nextWordId += 1;
|
2016-09-22 22:05:49 +02:00
|
|
|
|
|
|
|
this.setState({
|
|
|
|
words: updatedWords,
|
|
|
|
details: updatedDetails
|
|
|
|
}, () => {
|
|
|
|
if (this.showConsoleMessages) {
|
|
|
|
console.log('New word ' + newWord.name + ' added successfully');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Search the words list for the first word with the given idea and return its index in the array.
|
2016-09-24 16:58:09 +02:00
|
|
|
firstIndexWordWithId(id) {
|
2016-11-03 19:39:47 +01:00
|
|
|
this.state.words.forEach((word, index) => {
|
2016-09-24 16:58:09 +02:00
|
|
|
if (word.wordId === id) {
|
2016-11-03 19:39:47 +01:00
|
|
|
return index;
|
2016-09-23 02:08:14 +02:00
|
|
|
}
|
2016-11-03 19:39:47 +01:00
|
|
|
});
|
2016-09-24 16:58:09 +02:00
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
return -1;
|
2016-09-22 22:05:49 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Receive a wordId and a wordObject, find the index of the first word in the words state array with
|
|
|
|
// the given wordId, and set that word's values to the values in the given wordObject.
|
2016-09-24 16:58:09 +02:00
|
|
|
updateWord(wordId, wordObject) {
|
|
|
|
let index = this.firstIndexWordWithId(wordId);
|
2016-09-22 22:05:49 +02:00
|
|
|
|
2016-09-24 16:58:09 +02:00
|
|
|
if (index >= 0) {
|
|
|
|
if (this.showConsoleMessages) console.log('Updating ' + this.state.words[index].name + ' to ' + wordObject.name);
|
|
|
|
|
|
|
|
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;
|
2016-09-23 02:08:14 +02:00
|
|
|
|
2016-09-24 16:58:09 +02:00
|
|
|
updatedWords = this.sortWords(updatedWords);
|
|
|
|
|
|
|
|
this.setState({words: updatedWords}, () => {
|
|
|
|
if (this.showConsoleMessages) {
|
|
|
|
console.log('Updated successfully');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
console.log('Could not update. No word with id of ' + wordId.toString());
|
|
|
|
}
|
2016-09-22 22:05:49 +02:00
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Return true if the given dictionary reference has no words and its name and description are the same as the defaults.
|
2016-09-24 17:59:19 +02:00
|
|
|
dictionaryIsDefault(dictionary) {
|
|
|
|
if (this.showConsoleMessages) {
|
|
|
|
console.log('Name: ' + dictionary.name
|
|
|
|
+ '\nDescription: ' + dictionary.description
|
|
|
|
+ '\n# Words: ' + dictionary.words.length);
|
|
|
|
}
|
|
|
|
return dictionary.words.length <= 0 && dictionary.description === defaultDictionaryDescription && dictionary.name === defaultDictionaryName;
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Put the state details, words, and settings into an object, stringify it, and save it to the browser's localStorage as 'dictionary' if
|
|
|
|
// the dictionary in the state is not the default dictionary.
|
2016-09-24 17:59:19 +02:00
|
|
|
saveLocalDictionary() {
|
|
|
|
let saveDictionary = {
|
2016-11-03 19:39:47 +01:00
|
|
|
name: this.state.details.name
|
|
|
|
, listTypeName: this.state.details.listTypeName
|
|
|
|
, description: this.state.details.description
|
|
|
|
, createdBy: this.state.details.createdBy
|
|
|
|
, words: this.state.words
|
|
|
|
, nextWordId: this.state.details.nextWordId
|
|
|
|
, settings: this.state.settings
|
|
|
|
, externalID: this.state.details.externalID
|
2016-09-24 17:59:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (!this.dictionaryIsDefault(saveDictionary)) {
|
|
|
|
localStorage.setItem('dictionary', JSON.stringify(saveDictionary));
|
|
|
|
|
|
|
|
console.log('Saved "' + this.state.details.name + '" dictionary locally');
|
|
|
|
} else {
|
|
|
|
if (this.showConsoleMessages) console.log('Current dictionary is default, so it wasn\'t saved');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// If there is a saved 'dictionary' JSON string in localStorage, parse it, and set the state with its values.
|
2016-09-24 17:59:19 +02:00
|
|
|
loadLocalDictionary() {
|
|
|
|
if (localStorage.getItem('dictionary')){
|
|
|
|
let localDictionary = JSON.parse(localStorage.getItem('dictionary'));
|
|
|
|
|
|
|
|
if (!this.dictionaryIsDefault(localDictionary)) {
|
|
|
|
this.setState({
|
|
|
|
details: {
|
2016-11-03 19:39:47 +01:00
|
|
|
name: localDictionary.name
|
|
|
|
, listTypeName: localDictionary.listTypeName || defaultListTypeName
|
|
|
|
, description: localDictionary.description
|
|
|
|
, createdBy: localDictionary.createdBy
|
|
|
|
, nextWordId: localDictionary.nextWordId
|
|
|
|
, externalID: localDictionary.externalID
|
|
|
|
}
|
|
|
|
|
|
|
|
, words: localDictionary.words.slice()
|
|
|
|
|
|
|
|
, settings: {
|
|
|
|
allowDuplicates: localDictionary.settings.allowDuplicates
|
|
|
|
, caseSensitive: localDictionary.settings.caseSensitive
|
|
|
|
, partsOfSpeech: localDictionary.settings.partsOfSpeech
|
|
|
|
, sortByEquivalent: localDictionary.settings.sortByEquivalent
|
|
|
|
, isComplete: localDictionary.settings.isComplete
|
|
|
|
, isPublic: localDictionary.settings.isPublic
|
2016-09-24 17:59:19 +02:00
|
|
|
}
|
|
|
|
}, () => {
|
|
|
|
if (this.showConsoleMessages) {
|
|
|
|
console.log('Loaded local "' + this.state.details.name + '" dictionary successfully');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
if (this.showConsoleMessages) console.log('Locally saved dictionary is default');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (this.showConsoleMessages) console.log('No saved local dictionary');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Put all of the components together.
|
2016-09-21 22:40:25 +02:00
|
|
|
render() {
|
|
|
|
return (
|
2016-09-22 02:18:54 +02:00
|
|
|
<div>
|
|
|
|
<Header />
|
2016-09-22 22:05:49 +02:00
|
|
|
|
2016-09-27 23:12:48 +02:00
|
|
|
<div className='left-column'>
|
|
|
|
<div className='floating-form'>
|
|
|
|
<WordForm addWord={(wordObject) => this.addWord(wordObject)} submitLabel='Add Word' />
|
|
|
|
</div>
|
2016-09-22 22:05:49 +02:00
|
|
|
</div>
|
2016-09-27 23:12:48 +02:00
|
|
|
|
|
|
|
<div className='center-column'>
|
|
|
|
<Button
|
|
|
|
action={() => this.saveLocalDictionary()}
|
|
|
|
label='Save Dictionary' />
|
|
|
|
|
|
|
|
<Button
|
|
|
|
action={() => this.loadLocalDictionary()}
|
|
|
|
label='Load Dictionary' />
|
|
|
|
|
2016-09-28 01:10:03 +02:00
|
|
|
<EditDictionaryForm
|
|
|
|
details={this.state.details}
|
|
|
|
settings={this.state.settings}
|
|
|
|
saveChanges={(changesObject) => this.saveChanges(changesObject)} />
|
2016-09-27 23:12:48 +02:00
|
|
|
|
2016-09-30 04:26:16 +02:00
|
|
|
<h1 className="dictionary-name">
|
2016-09-30 06:59:25 +02:00
|
|
|
{this.state.details.name} {this.state.details.listTypeName}
|
2016-09-30 04:26:16 +02:00
|
|
|
</h1>
|
|
|
|
|
|
|
|
<InfoDisplay
|
|
|
|
details={this.state.details}
|
|
|
|
numberOfWords={this.state.words.length}
|
|
|
|
isComplete={this.state.settings.isComplete} />
|
|
|
|
|
2016-09-27 23:12:48 +02:00
|
|
|
<Dictionary
|
|
|
|
details={this.state.details}
|
|
|
|
words={this.state.words}
|
|
|
|
settings={this.state.settings}
|
|
|
|
updateWord={(wordId, wordObject) => this.updateWord(wordId, wordObject)} />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Footer />
|
2016-09-22 02:18:54 +02:00
|
|
|
</div>
|
2016-09-21 22:40:25 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 19:39:47 +01:00
|
|
|
// Put the app on the screen.
|
2016-09-22 22:05:49 +02:00
|
|
|
ReactDOM.render(<Lexiconga showConsoleMessages={true} />, document.getElementById('site'));
|