2019-06-06 11:25:08 -06:00
import papa from 'papaparse' ;
2019-07-08 15:49:46 -06:00
import { renderDictionaryDetails , renderPartsOfSpeech } from "./render/details" ;
2019-07-10 14:59:37 -06:00
import { renderAll , renderTheme , renderCustomCSS } from "./render" ;
2019-05-10 15:39:00 -06:00
import { removeTags , cloneObject , getTimestampInSeconds , download , slugify } from "../helpers" ;
2019-07-05 09:39:30 -06:00
import { LOCAL _STORAGE _KEY , DEFAULT _DICTIONARY } from "../constants" ;
2019-07-09 17:03:52 -06:00
import { addMessage , getNextId , hasToken , objectValuesAreDifferent } from "./utilities" ;
2019-05-24 14:01:48 -06:00
import { addWord , sortWords } from "./wordManagement" ;
2019-07-05 09:39:30 -06:00
import { migrateDictionary } from './migration' ;
2019-05-03 21:52:19 -06:00
export function updateDictionary ( ) {
renderDictionaryDetails ( ) ;
}
export function openEditModal ( ) {
2019-07-09 13:06:03 -06:00
const { name , specification , description , partsOfSpeech , alphabeticalOrder } = window . currentDictionary ;
2019-07-10 12:14:27 -06:00
const { phonology , phonotactics , orthography , grammar } = window . currentDictionary . details ;
const { consonants , vowels , blends } = phonology ;
2019-07-10 14:59:37 -06:00
const { allowDuplicates , caseSensitive , sortByDefinition , theme , customCSS , isPublic } = window . currentDictionary . settings ;
2019-05-03 23:58:49 -06:00
document . getElementById ( 'editName' ) . value = name ;
document . getElementById ( 'editSpecification' ) . value = specification ;
document . getElementById ( 'editDescription' ) . value = description ;
document . getElementById ( 'editPartsOfSpeech' ) . value = partsOfSpeech . join ( ',' ) ;
2019-07-09 13:06:03 -06:00
document . getElementById ( 'editAlphabeticalOrder' ) . value = alphabeticalOrder . join ( ' ' ) ;
2019-05-03 23:58:49 -06:00
2019-05-10 15:52:20 -06:00
document . getElementById ( 'editConsonants' ) . value = consonants . join ( ' ' ) ;
document . getElementById ( 'editVowels' ) . value = vowels . join ( ' ' ) ;
document . getElementById ( 'editBlends' ) . value = blends . join ( ' ' ) ;
2019-07-10 12:14:27 -06:00
document . getElementById ( 'editPhonologyNotes' ) . value = phonology . notes ;
2019-05-03 23:58:49 -06:00
document . getElementById ( 'editOnset' ) . value = phonotactics . onset . join ( ',' ) ;
document . getElementById ( 'editNucleus' ) . value = phonotactics . nucleus . join ( ',' ) ;
document . getElementById ( 'editCoda' ) . value = phonotactics . coda . join ( ',' ) ;
2019-07-05 11:44:53 -06:00
document . getElementById ( 'editPhonotacticsNotes' ) . value = phonotactics . notes ;
2019-05-03 23:58:49 -06:00
2019-07-05 14:51:36 -06:00
document . getElementById ( 'editTranslations' ) . value = orthography . translations . join ( '\n' ) ;
2019-05-03 23:58:49 -06:00
document . getElementById ( 'editOrthography' ) . value = orthography . notes ;
document . getElementById ( 'editGrammar' ) . value = grammar . notes ;
2019-05-06 14:30:57 -06:00
document . getElementById ( 'editPreventDuplicates' ) . checked = ! allowDuplicates ;
2019-05-04 00:21:55 -06:00
document . getElementById ( 'editCaseSensitive' ) . checked = caseSensitive ;
2019-05-06 14:30:57 -06:00
if ( allowDuplicates ) document . getElementById ( 'editCaseSensitive' ) . disabled = true ;
2019-05-04 00:21:55 -06:00
document . getElementById ( 'editSortByDefinition' ) . checked = sortByDefinition ;
2019-05-31 13:11:01 -06:00
document . getElementById ( 'editTheme' ) . value = theme ;
2019-07-10 14:59:37 -06:00
document . getElementById ( 'editCustomCSS' ) . value = customCSS ;
2019-05-24 15:37:15 -06:00
if ( hasToken ( ) ) {
document . getElementById ( 'editIsPublic' ) . checked = isPublic ;
}
2019-05-04 00:21:55 -06:00
document . getElementById ( 'editModal' ) . style . display = '' ;
2020-08-03 16:33:56 -06:00
Array . from ( document . querySelectorAll ( '#editModal .modal-content section' ) ) . forEach ( section => section . scrollTop = 0 ) ;
2019-05-04 00:21:55 -06:00
}
2019-05-08 15:23:46 -06:00
export function saveEditModal ( ) {
2019-07-09 17:03:52 -06:00
const updatedDictionary = cloneObject ( window . currentDictionary ) ;
delete updatedDictionary . words ;
updatedDictionary . name = removeTags ( document . getElementById ( 'editName' ) . value . trim ( ) ) ;
2019-07-10 13:23:32 -06:00
if ( updatedDictionary . name . length < 1 ) {
updatedDictionary . name = window . currentDictionary . name ;
}
2019-07-09 17:03:52 -06:00
updatedDictionary . specification = removeTags ( document . getElementById ( 'editSpecification' ) . value . trim ( ) ) ;
2019-07-10 13:23:32 -06:00
if ( updatedDictionary . specification . length < 1 ) {
updatedDictionary . specification = window . currentDictionary . specification ;
}
2019-07-09 17:03:52 -06:00
updatedDictionary . description = removeTags ( document . getElementById ( 'editDescription' ) . value . trim ( ) ) ;
updatedDictionary . partsOfSpeech = document . getElementById ( 'editPartsOfSpeech' ) . value . split ( ',' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . alphabeticalOrder = document . getElementById ( 'editAlphabeticalOrder' ) . value . split ( ' ' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonology . consonants = document . getElementById ( 'editConsonants' ) . value . split ( ' ' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonology . vowels = document . getElementById ( 'editVowels' ) . value . split ( ' ' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonology . blends = document . getElementById ( 'editBlends' ) . value . split ( ' ' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
2019-07-10 12:14:27 -06:00
updatedDictionary . details . phonology . notes = removeTags ( document . getElementById ( 'editPhonologyNotes' ) . value . trim ( ) ) ;
2019-07-09 17:03:52 -06:00
updatedDictionary . details . phonotactics . onset = document . getElementById ( 'editOnset' ) . value . split ( ',' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonotactics . nucleus = document . getElementById ( 'editNucleus' ) . value . split ( ',' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonotactics . coda = document . getElementById ( 'editCoda' ) . value . split ( ',' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . phonotactics . notes = removeTags ( document . getElementById ( 'editPhonotacticsNotes' ) . value . trim ( ) ) ;
updatedDictionary . details . orthography . translations = document . getElementById ( 'editTranslations' ) . value . split ( '\n' ) . map ( val => val . trim ( ) ) . filter ( val => val !== '' ) ;
updatedDictionary . details . orthography . notes = removeTags ( document . getElementById ( 'editOrthography' ) . value . trim ( ) ) ;
updatedDictionary . details . grammar . notes = removeTags ( document . getElementById ( 'editGrammar' ) . value . trim ( ) ) ;
updatedDictionary . settings . allowDuplicates = ! document . getElementById ( 'editPreventDuplicates' ) . checked ;
updatedDictionary . settings . caseSensitive = document . getElementById ( 'editCaseSensitive' ) . checked ;
updatedDictionary . settings . sortByDefinition = document . getElementById ( 'editSortByDefinition' ) . checked ;
updatedDictionary . settings . theme = document . getElementById ( 'editTheme' ) . value ;
2019-07-10 14:59:37 -06:00
updatedDictionary . settings . customCSS = removeTags ( document . getElementById ( 'editCustomCSS' ) . value . trim ( ) ) ;
2019-05-30 14:21:09 -06:00
2019-05-24 15:37:15 -06:00
if ( hasToken ( ) ) {
2019-07-09 17:03:52 -06:00
updatedDictionary . settings . isPublic = document . getElementById ( 'editIsPublic' ) . checked ;
2019-05-24 15:37:15 -06:00
} else {
2019-07-09 17:03:52 -06:00
updatedDictionary . settings . isPublic = false ;
2019-05-24 15:37:15 -06:00
}
2019-05-24 14:01:48 -06:00
2019-07-09 17:03:52 -06:00
if ( objectValuesAreDifferent ( updatedDictionary , window . currentDictionary ) ) {
window . currentDictionary = Object . assign ( window . currentDictionary , updatedDictionary ) ;
2019-07-09 13:06:03 -06:00
2019-07-09 17:03:52 -06:00
renderTheme ( ) ;
2019-07-10 14:59:37 -06:00
renderCustomCSS ( ) ;
2019-07-09 17:03:52 -06:00
renderDictionaryDetails ( ) ;
renderPartsOfSpeech ( ) ;
sortWords ( true ) ;
addMessage ( 'Saved ' + window . currentDictionary . specification + ' Successfully' ) ;
saveDictionary ( ) ;
if ( hasToken ( ) ) {
import ( './account/index.js' ) . then ( account => {
account . uploadDetailsDirect ( ) ;
account . updateChangeDictionaryOption ( ) ;
} )
}
} else {
addMessage ( 'No changes made to Dictionary Settings.' ) ;
2019-05-23 12:03:25 -06:00
}
2019-05-04 00:21:55 -06:00
}
2019-05-08 15:23:46 -06:00
export function saveAndCloseEditModal ( ) {
saveEditModal ( ) ;
2019-05-04 00:21:55 -06:00
document . getElementById ( 'editModal' ) . style . display = 'none' ;
2019-05-03 21:52:19 -06:00
}
2019-05-23 14:26:57 -06:00
export function saveDictionary ( triggerLastUpdated = true ) {
if ( triggerLastUpdated ) {
window . currentDictionary . lastUpdated = getTimestampInSeconds ( ) ;
}
2019-05-08 15:23:46 -06:00
window . localStorage . setItem ( LOCAL _STORAGE _KEY , JSON . stringify ( window . currentDictionary ) ) ;
}
2019-05-03 21:52:19 -06:00
2019-05-08 15:23:46 -06:00
export function loadDictionary ( ) {
const storedDictionary = window . localStorage . getItem ( LOCAL _STORAGE _KEY ) ;
if ( storedDictionary ) {
window . currentDictionary = JSON . parse ( storedDictionary ) ;
2019-05-08 16:19:11 -06:00
migrateDictionary ( ) ;
2019-05-08 15:23:46 -06:00
} else {
clearDictionary ( ) ;
}
}
export function clearDictionary ( ) {
window . currentDictionary = cloneObject ( DEFAULT _DICTIONARY ) ;
2019-05-31 13:11:01 -06:00
window . currentDictionary . settings . theme = window . settings . defaultTheme ;
2019-05-08 15:23:46 -06:00
}
2019-05-08 16:19:11 -06:00
2019-05-13 10:49:52 -06:00
export function deleteDictionary ( ) {
2019-05-23 19:56:45 -06:00
const deletedId = window . currentDictionary . externalID ;
2019-05-13 10:49:52 -06:00
clearDictionary ( ) ;
saveDictionary ( ) ;
addMessage ( 'Dictionary Deleted!' ) ;
renderAll ( ) ;
2019-05-23 19:56:45 -06:00
if ( hasToken ( ) ) {
import ( './account/index.js' ) . then ( account => {
account . deleteCurrentDictionary ( deletedId ) ;
} ) ;
}
2019-05-13 10:49:52 -06:00
}
export function confirmDeleteDictionary ( ) {
if ( confirm ( ` Are you sure you want to delete your ${ window . currentDictionary . name } ${ window . currentDictionary . specification } ? \n \n This cannot be undone! ` ) ) {
const input = prompt ( ` If you really want to delete your ${ window . currentDictionary . name } ${ window . currentDictionary . specification } please type DELETE in the text box. \n \n After you confirm, cour dicitonary will be PERMANENTLY AND IRRETRIEVABLY DESTROYED! ` ) ;
2019-06-10 12:39:45 -06:00
2019-05-13 10:49:52 -06:00
if ( input === 'DELETE' ) {
deleteDictionary ( ) ;
document . getElementById ( 'editModal' ) . style . display = 'none' ;
} else {
alert ( 'Your dictionary was NOT deleted' ) ;
}
}
}
2019-05-10 15:39:00 -06:00
export function importDictionary ( ) {
const importDictionaryField = document . getElementById ( 'importDictionaryFile' ) ;
if ( importDictionaryField . files . length === 1 ) {
if ( confirm ( 'Importing a dicitonary file will overwrite and replace your current dictionary!\nDo you want to continue?' ) ) {
addMessage ( 'Importing Dictionary...' ) ;
const fileReader = new FileReader ( ) ;
fileReader . onload = function ( fileLoadedEvent ) {
const textFromFileLoaded = fileLoadedEvent . target . result ;
const importedDictionary = JSON . parse ( textFromFileLoaded ) ;
if ( importedDictionary && importedDictionary . hasOwnProperty ( 'words' ) ) {
2019-05-23 14:42:09 -06:00
const timestamp = getTimestampInSeconds ( ) ;
if ( ! importedDictionary . hasOwnProperty ( 'createdOn' ) ) {
importedDictionary . createdOn = timestamp ;
}
if ( importedDictionary . words . some ( word => ! word . hasOwnProperty ( 'createdOn' ) ) ) {
importedDictionary . words . forEach ( word => {
if ( ! word . hasOwnProperty ( 'createdOn' ) ) {
word . createdOn = timestamp ;
}
if ( ! word . hasOwnProperty ( 'lastUpdated' ) ) {
word . lastUpdated = timestamp ;
}
} ) ;
}
if ( importedDictionary . hasOwnProperty ( 'externalID' ) ) {
delete importedDictionary . externalID ;
}
2019-05-10 15:39:00 -06:00
window . currentDictionary = importedDictionary ;
saveDictionary ( ) ;
renderAll ( ) ;
importDictionaryField . value = '' ;
document . getElementById ( 'editModal' ) . style . display = 'none' ;
addMessage ( 'Dictionary Imported Successfully' ) ;
2019-05-23 12:03:25 -06:00
if ( hasToken ( ) ) {
import ( './account/index.js' ) . then ( account => {
account . syncImportedDictionary ( ) ;
} ) ;
}
2019-05-10 15:39:00 -06:00
} else {
2019-05-23 15:24:56 -06:00
addMessage ( 'Dictionary could not be imported' , 10000 , 'error' ) ;
2019-05-10 15:39:00 -06:00
}
} ;
fileReader . readAsText ( importDictionaryField . files [ 0 ] , "UTF-8" ) ;
}
}
}
export function importWords ( ) {
const importWordsField = document . getElementById ( 'importWordsCSV' ) ;
if ( importWordsField . files . length === 1 ) {
if ( confirm ( 'Importing a CSV file with words will add all of the words in the file to your dictionary regardless of duplication!\nDo you want to continue?' ) ) {
addMessage ( 'Importing words...' ) ;
2019-06-06 11:25:08 -06:00
const importedWords = [ ] ;
papa . parse ( importWordsField . files [ 0 ] , {
header : true ,
encoding : "utf-8" ,
step : results => {
if ( results . errors . length > 0 ) {
results . errors . forEach ( err => {
addMessage ( 'Error Importing Word: ' + err , undefined , 'error' ) ;
console . error ( 'Error Importing Word: ' , err )
} ) ;
} else {
2020-03-04 09:54:37 -07:00
const row = results . data ;
2020-07-31 16:25:26 -06:00
const wordToImport = {
2019-06-06 11:25:08 -06:00
name : removeTags ( row . word ) . trim ( ) ,
pronunciation : removeTags ( row . pronunciation ) . trim ( ) ,
partOfSpeech : removeTags ( row [ 'part of speech' ] ) . trim ( ) ,
definition : removeTags ( row . definition ) . trim ( ) ,
details : removeTags ( row . explanation ) . trim ( ) ,
wordId : getNextId ( ) ,
2020-07-31 16:25:26 -06:00
} ;
if ( typeof row [ 'etymology' ] !== 'undefined' ) {
const etymology = removeTags ( row [ 'etymology' ] ) . trim ( ) . split ( ',' ) . filter ( etymology => etymology . trim ( ) !== '' ) ;
if ( etymology . length > 0 ) {
wordToImport . etymology = etymology ;
}
}
if ( typeof row [ 'etymology (comma-separated)' ] !== 'undefined' ) {
const etymology = removeTags ( row [ 'etymology (comma-separated)' ] ) . trim ( ) . split ( ',' ) . filter ( etymology => etymology . trim ( ) !== '' ) ;
if ( etymology . length > 0 ) {
wordToImport . etymology = etymology ;
}
}
if ( typeof row [ 'related words' ] !== 'undefined' ) {
const related = removeTags ( row [ 'related words' ] ) . trim ( ) . split ( ',' ) . filter ( related => related . trim ( ) !== '' ) ;
if ( related . length > 0 ) {
wordToImport . related = related ;
}
}
if ( typeof row [ 'related words (comma-separated)' ] !== 'undefined' ) {
const related = removeTags ( row [ 'related words (comma-separated)' ] ) . trim ( ) . split ( ',' ) . filter ( related => related . trim ( ) !== '' ) ;
if ( related . length > 0 ) {
wordToImport . related = related ;
}
}
if ( typeof row [ 'principal parts' ] !== 'undefined' ) {
const principalParts = removeTags ( row [ 'principal parts' ] ) . trim ( ) . split ( ',' ) . filter ( principalParts => principalParts . trim ( ) !== '' ) ;
if ( principalParts . length > 0 ) {
wordToImport . principalParts = principalParts ;
}
}
if ( typeof row [ 'principal parts (comma-separated)' ] !== 'undefined' ) {
const principalParts = removeTags ( row [ 'principal parts (comma-separated)' ] ) . trim ( ) . split ( ',' ) . filter ( principalParts => principalParts . trim ( ) !== '' ) ;
if ( principalParts . length > 0 ) {
wordToImport . principalParts = principalParts ;
}
}
const importedWord = addWord ( wordToImport , false ) ;
2019-06-06 11:25:08 -06:00
importedWords . push ( importedWord ) ;
2019-07-19 09:48:36 -06:00
// Sort and save every 500 words, just in case something goes wrong on large imports
if ( importedWords . length % 500 == 499 ) {
sortWords ( false ) ;
}
2019-06-06 11:25:08 -06:00
}
} ,
complete : ( ) => {
2019-07-19 09:48:36 -06:00
sortWords ( false ) ;
2019-06-06 11:25:08 -06:00
renderAll ( ) ;
importWordsField . value = '' ;
document . getElementById ( 'editModal' ) . style . display = 'none' ;
addMessage ( ` Done Importing ${ importedWords . length } Words ` ) ;
if ( hasToken ( ) ) {
import ( './account/index.js' ) . then ( account => {
account . syncImportedWords ( importedWords ) ;
} ) ;
}
} ,
error : err => {
addMessage ( 'Error Importing Words: ' + err , undefined , 'error' ) ;
console . error ( 'Error Importing Words: ' , err ) ;
} ,
skipEmptyLines : true ,
2019-05-10 15:39:00 -06:00
} ) ;
}
}
}
export function exportDictionary ( ) {
addMessage ( 'Exporting JSON...' ) ;
setTimeout ( ( ) => {
const file = JSON . stringify ( window . currentDictionary ) ,
{ name , specification } = window . currentDictionary ;
const fileName = slugify ( name + '_' + specification ) + '.json' ;
download ( file , fileName , 'application/json;charset=utf-8' ) ;
} , 1 ) ;
}
export function exportWords ( ) {
addMessage ( 'Exporting Words...' ) ;
setTimeout ( ( ) => {
2019-06-06 11:25:08 -06:00
const { name , specification } = window . currentDictionary ;
const fileName = slugify ( name + '_' + specification ) + '_words.csv' ;
const words = window . currentDictionary . words . map ( word => {
return {
word : word . name ,
pronunciation : word . pronunciation ,
'part of speech' : word . partOfSpeech ,
definition : word . definition ,
explanation : word . details ,
2020-07-31 16:25:26 -06:00
'etymology (comma-separated)' : typeof word . etymology !== 'undefined' ? word . etymology . join ( ',' ) : '' ,
'related words (comma-separated)' : typeof word . related !== 'undefined' ? word . related . join ( ',' ) : '' ,
'principal parts (comma-separated)' : typeof word . principalParts !== 'undefined' ? word . principalParts . join ( ',' ) : '' ,
2019-06-06 11:25:08 -06:00
}
2019-05-10 15:39:00 -06:00
} ) ;
2019-06-06 11:25:08 -06:00
const csv = papa . unparse ( words , { quotes : true } ) ;
download ( csv , fileName , 'text/csv;charset=utf-8' ) ;
2019-05-10 15:39:00 -06:00
} , 1 ) ;
}