I am trying to learn vocabulary in my own way. I have created this page that modifies the input sentence by placing the meanings next to the difficult words (in parenthesis) in that sentence. This way, I can learn vocabulary in context. I have added different features and want to add one last feature: making the difficult words in the sentence clickable and pasting them into the next input field, so there’s no need to type those words again. I have tried it, but my code is not working. Here’s my code:
document.getElementById("sentence").focus();
function modifySentence() {
const sentence = document.getElementById("sentence").value.trim();
const wordMeaningsInput = document.getElementById("wordMeanings").value.trim();
if (!sentence || !wordMeaningsInput) {
alert("Please enter both a sentence and word-meaning pairs.");
return;
}
const wordMeanings = {};
const lines = wordMeaningsInput.split('n');
for (const line of lines) {
const [word, meaningsStr] = line.split(':').map(s => s.trim());
if (word && meaningsStr) {
wordMeanings[word] = meaningsStr.split(',').map(s => s.trim());
}
}
let modifiedSentence = sentence;
for (const word in wordMeanings) {
const meanings = wordMeanings[word];
const replacement = `<b>${word} (${meanings.join(', ')})</b>`;
modifiedSentence = modifiedSentence.replace(new RegExp(`\b${word}\b`, 'gi'), replacement);
}
document.getElementById("modifiedsentence").innerHTML = modifiedSentence;
const formattedSentence = document.getElementById("modifiedsentence").innerHTML;
addToHistory(formattedSentence);
document.getElementById("sentence").value = "";
document.getElementById("wordMeanings").value = "";
}
function addToHistory(sentence) {
const historyList = document.getElementById("history");
const listItem = document.createElement("li");
listItem.innerHTML = sentence;
historyList.appendChild(listItem);
}
function copyHistoryToClipboard() {
const historyList = document.getElementById("history");
const range = document.createRange();
range.selectNodeContents(historyList);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand("copy");
window.getSelection().removeAllRanges();
const copySuccessMessage = document.getElementById("copySuccessMessage");
copySuccessMessage.style.display = "block";
setTimeout(() => {
copySuccessMessage.style.display = "none";
}, 1500);
}
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 'Enter') {
modifySentence();
}
});
document.getElementById("modifiedsentence").addEventListener("click", function() {
document.getElementById("sentence").focus();
});
function handleWordClick(clickedWord) {
const wordMeaningsTextArea = document.getElementById("wordMeanings");
const existingText = wordMeaningsTextArea.value;
if (!existingText.includes(clickedWord + ":")) {
wordMeaningsTextArea.value += (existingText ? "n" : "") + clickedWord + ": ";
// Highlight the clicked word WITHOUT re-wrapping all words:
const sentenceInput = document.getElementById("sentence");
const wordElements = sentenceInput.querySelectorAll('span'); // Get all existing spans
wordElements.forEach(wordElement => {
if (wordElement.textContent === clickedWord && !wordElement.classList.contains('highlighted')) {
wordElement.classList.add('highlighted');
}
});
wordMeaningsTextArea.focus();
}
}
function wrapWordsInSpans(sentenceInputId) {
const sentenceInput = document.getElementById(sentenceInputId);
const sentenceText = sentenceInput.value;
const words = sentenceText.split(/s+/);
// Create a temporary element to hold the wrapped words
const tempSpan = document.createElement('span');
tempSpan.innerHTML = words.map(word => {
// Check if the word is already highlighted
const isHighlighted = sentenceInput.querySelector(`span.highlighted:contains("${word}")`);
// Wrap with or without the highlighted class
return isHighlighted ?
`<span class="highlighted" onclick="handleWordClick('${word}')">${word}</span>` :
`<span onclick="handleWordClick('${word}')">${word}</span>`;
}).join(" ");
// Replace the content of the input with the wrapped words
sentenceInput.innerHTML = tempSpan.innerHTML;
}
document.getElementById("sentence").addEventListener("input", function() {
wrapWordsInSpans("sentence");
});
#one {
margin-left: auto;
margin-right: auto;
width: 90%;
}
.copy-success {
display: none;
color: green;
font-weight: bold;
margin-top: 5px;
}
/* Style for modified sentence and history */
#modifiedsentence,
#history li {
font-family: Arial, sans-serif;
font-size: 12pt;
}
/* Style for highlighted words */
.highlighted {
background-color: yellow;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div align="center">
<h1>Meaning In Sentence</h1>
<div>
<h3>Sentence:</h3>
<input type="text" id="sentence" class="form-control" style="width:80%" placeholder="Enter the sentence containing difficult words" autofocus>
</div>
<br>
<h3>Difficult Words and Meanings:</h3>
<textarea id="wordMeanings" class="form-control" style="width:80%" placeholder="Enter difficult words and their meanings (one word-meaning pair per line, separated by ':').
For multiple meanings, separate them by commas.
Example: word1: meaning1, meaning2
word2: meaning3"></textarea>
<br>
<div align="center">
<button type="button" class="btn btn-default" onclick="modifySentence()" id="modifyButton">Modify Sentence</button>
<button type="button" class="btn btn-default" onclick="copyHistoryToClipboard()">Copy History</button>
<div class="copy-success" id="copySuccessMessage">Copied!</div>
</div>
<br>
<div class="h4" align="center">
<h3>Modified Sentence:</h3>
<p id="modifiedsentence"></p>
</div>
<div id="historySection">
<h3>History:</h3>
<ul id="history"></ul>
</div>
</div>
5
In order to make the words clickable I came up with an idea, try this:
First create an invisible input:
<input id="input-text" style="opacity: 0; width: 0; height: 0;"/>
Then add a div as follow:
<div id="words-container" style="width: 500px; height: 300px; border: 1px solid black; display: flex;"></div>
This div will contain the words, and the words will be spans
So in your js file listen to click events on #words-container, so when it triggers you add a focus to the input.
document.getElementById('words-container').addEventListener('click', function() {
document.getElementById('input-text').focus();
});
Now detect when you type on the invisible input:
document.getElementById('input').addEventListener('keydown', function(event) {
if (event.code === 'Space') {
event.preventDefault(); // Prevent the space from being added
const inputElement = event.target;
const inputText = inputElement.value.trim(); // Clear additional empty space (just in case)
if (inputText.length > 0) {
// Create the span
const span = document.createElement('span');
span.className = 'word';
span.textContent = inputText;
// Add the span to the container
document.getElementById('words-container').appendChild(span);
// Clear the input
inputElement.value = '';
}
}
});
And with this way you can add a click listener for spans with the class of “word”.
document.getElementById('words-container').addEventListener('click', function(event) {
// Verify the click was on word span
if (event.target.classList.contains('word')) {
// Do your thing
}
});
So the next problem is the cursor indicator of the input, I’m talking about the “|”, you can easily add it like this inside the words-container:
<span id="cursor">|</span>
Then you need to programmatically make it blink every X time, and move it to the next word.
You can improve this code by adding each character into the container for better user experience. Since the words wouldn’t be visible until you press “Space”.