Add words to dictionary with validation
This commit is contained in:
parent
88c522ea1b
commit
a670abf24c
10
index.html
10
index.html
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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, '<');
|
return html.replace(/</g, '<');
|
||||||
|
}
|
||||||
|
return html;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue