Add words to dictionary with validation

This commit is contained in:
Robbie Antenesse 2019-05-03 16:10:41 -06:00
parent 88c522ea1b
commit a670abf24c
7 changed files with 120 additions and 24 deletions

View File

@ -49,8 +49,8 @@
<main> <main>
<aside id="sideColumn"> <aside id="sideColumn">
<form id="wordForm" onsubmit="function(e){e.preventDefault();return false;}"> <form id="wordForm">
<label>Word<br> <label>Word<span class="red">*</span><br>
<input id="wordName"> <input id="wordName">
</label> </label>
<label>Pronunciation<a class="label-button">IPA Chart</a><br> <label>Pronunciation<a class="label-button">IPA Chart</a><br>
@ -59,12 +59,14 @@
<label>Part of Speech<br> <label>Part of Speech<br>
<select id="wordPartOfSpeech" class="part-of-speech-select"></select> <select id="wordPartOfSpeech" class="part-of-speech-select"></select>
</label> </label>
<label>Definition<br> <label>Definition<span class="red">*</span><br>
<input id="wordDefinition" placeholder="Equivalent words"> <input id="wordDefinition" placeholder="Equivalent words">
</label> </label>
<label>Details<a class="label-button">Maximize</a><br> <label>Details<span class="red">*</span><a class="label-button">Maximize</a><br>
<textarea id="wordDetails" placeholder="Markdown formatting allowed"></textarea> <textarea id="wordDetails" placeholder="Markdown formatting allowed"></textarea>
</label> </label>
<div id="wordErrorMessage"></div>
<a class="button" id="addWordButton">Add Word</a>
</form> </form>
</aside> </aside>

View File

@ -3,24 +3,26 @@ export function cloneObject(object) {
} }
export function removeTags(html) { export function removeTags(html) {
var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*'; if (html) {
var tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*';
var tagOrComment = new RegExp( var tagOrComment = new RegExp(
'<(?:' '<(?:'
// Comment body. // Comment body.
+ '!--(?:(?:-*[^->])*--+|-?)' + '!--(?:(?:-*[^->])*--+|-?)'
// Special "raw text" elements whose content should be elided. // Special "raw text" elements whose content should be elided.
+ '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*' + '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*'
+ '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*' + '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*'
// Regular name // Regular name
+ '|/?[a-z]' + '|/?[a-z]'
+ tagBody + tagBody
+ ')>', + ')>',
'gi'); 'gi');
var oldHtml; var oldHtml;
do { do {
oldHtml = html; oldHtml = html;
html = html.replace(tagOrComment, ''); html = html.replace(tagOrComment, '');
} while (html !== oldHtml); } while (html !== oldHtml);
return html.replace(/</g, '&lt;'); return html.replace(/</g, '&lt;');
}
return html;
} }

View File

@ -1,9 +1,13 @@
import {showSection} from './displayToggles'; import {showSection} from './displayToggles';
import { renderWords } from './render'; import { renderWords } from './render';
import { validateWord, addWord } from './wordManagement';
import { removeTags } from '../helpers';
import { getNextId } from './utilities';
export default function setupListeners() { export default function setupListeners() {
setupDetailsTabs(); setupDetailsTabs();
setupSearchBar(); setupSearchBar();
setupWordForm();
} }
function setupDetailsTabs() { function setupDetailsTabs() {
@ -42,3 +46,33 @@ function setupSearchBar() {
document.getElementById('searchModal').style.display = 'block'; document.getElementById('searchModal').style.display = 'block';
}); });
} }
function setupWordForm() {
const wordForm = document.getElementById('wordForm'),
addWordButton = document.getElementById('addWordButton');
wordForm.addEventListener('submit', event => {
// Allow semantic form and prevent it from getting submitted
event.preventDefault();
return false;
});
addWordButton.addEventListener('click', () => {
const name = document.getElementById('wordName').value,
pronunciation = document.getElementById('wordPronunciation').value,
partOfSpeech = document.getElementById('wordPartOfSpeech').value,
definition = document.getElementById('wordDefinition').value,
details = document.getElementById('wordDetails').value;
const word = {
name: removeTags(name).trim(),
pronunciation: removeTags(pronunciation).trim(),
partOfSpeech: removeTags(partOfSpeech).trim(),
simpleDefinition: removeTags(definition).trim(),
longDefinition: removeTags(details).trim(),
wordId: getNextId(),
};
if (validateWord(word)) {
addWord(word);
}
});
}

View File

@ -1,5 +1,12 @@
import { cloneObject } from '../helpers'; import { cloneObject } from '../helpers';
export function getNextId() {
const lastId = window.currentDictionary.words.reduce((highestId, word) => {
return (word.wordId && word.wordId) > highestId ? word.wordId : highestId;
}, 0);
return lastId + 1;
}
export function getWordsStats() { export function getWordsStats() {
const {words, partsOfSpeech} = window.currentDictionary; const {words, partsOfSpeech} = window.currentDictionary;
const {caseSensitive} = window.currentDictionary.settings; const {caseSensitive} = window.currentDictionary.settings;

39
src/js/wordManagement.js Normal file
View File

@ -0,0 +1,39 @@
import { renderWords } from "./render";
import { wordExists } from "./utilities";
export function validateWord(word, wordId = false) {
const errorElementId = wordId === false ? 'wordErrorMessage' : 'wordErrorMessage_' + wordId,
errorElement = document.getElementById(errorElementId);
let errorMessage = '';
if (word.name === '') {
errorMessage += '<p class="bold red">Word field must not be blank.</p>';
}
if (word.simpleDefinition === '' && word.longDefinition === '') {
errorMessage += '<p class="bold red">You must enter Definition or Details.</p>';
}
const { allowDuplicates, caseSensitive } = window.currentDictionary.settings;
if (!allowDuplicates) {
const foundDuplicate = wordExists(word.name, true);
if (foundDuplicate !== false) {
errorMessage += `<p class="bold red">"<a href="#${foundDuplicate}">${word.name}</a>" already exists, and "Allow Duplicates" is turned off.${!caseSensitive ? ' <em>(Case sensitivity is turned also off)</em>' : ''}</p>`;
}
}
errorElement.innerHTML = errorMessage;
return errorMessage === '';
}
export function addWord(word) {
const { sortByDefinition } = window.currentDictionary.settings;
const sortBy = sortByDefinition ? 'simpleDefinition' : 'name';
window.currentDictionary.words.push(word);
window.currentDictionary.words.sort((wordA, wordB) => {
if (wordA[sortBy] === wordB[sortBy]) return 0;
return wordA[sortBy] > wordB[sortBy] ? 1 : -1;
});
renderWords();
}

View File

@ -1,3 +1,13 @@
p, span {
&.red {
color: $red;
}
&.bold {
font-weight: bold;
}
}
.tag { .tag {
padding: 3px 9px; padding: 3px 9px;
border: $border; border: $border;

View File

@ -51,6 +51,8 @@
background-color: $light; background-color: $light;
border: $border; border: $border;
border-radius: 5px; border-radius: 5px;
max-height: 80%;
overflow-y: auto;
label { label {
display: block; display: block;