I'm trying to show/hide some text (a highlight) in the middle of a paragraph. These criteria are essential:
line-height.Below are what I have so far but neither is quite right. Version 1 has the transition I would prefer i.e. width of the <mark> tag reducing to zero and using an overflow: hidden to mask the text as it is reducing is size. The problem with this is it can't be multi-line. Version 2 is a compromise that reduces font-size: 0px; but can be multi-line.
Is there any solution to getting this to work (looking like version 1 but functioning like version 2)? Or is there another solution to this? (I have also tried transform: scaleX(0); and this does not work).
body
{
font-size: 15px;
line-height: 21px;
font-family: 'Open Sans';
}
.section
{
position: relative;
margin: 0px 0px 50px 0px;
width: 500px;
height: 210px;
background: #eeeeee;
border: 1px solid #666666;
}
.paragraph
{
position: relative;
width: 100%;
height: 100%;
display: inline;
vertical-align: middle;
}
.paragraph1
{
background: #00ffff;
}
.paragraph2
{
background: #00ffff;
}
/* version 1 */
.mark1
{
position: relative;
top: 2px;
width: 150px;
height: 21px;
transition: all 1.0s;
vertical-align: bottom;
display: inline-block;
overflow: hidden;
white-space: pre;
}
.mark1 span
{
position: relative;
top: -2px;
height: 23px;
display: inline-block;
background: #cccccc;
}
.mark1.hidden
{
width: 0px;
transition: all 1.0s;
}
/* version 2 */
.mark2
{
position: relative;
transition: all 1.0s;
vertical-align: bottom;
background: #00ff00;
}
.mark2 span
{
position: relative;
padding: 0px 0px 0px 0px;
background: #cccccc;
}
.mark2.hidden
{
font-size: 0px;
transition: all 1.0s;
}
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>example</title>
<link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
</head>
<body>
<button onclick="
const collection = document.getElementsByClassName('mark1');
for (let i = 0; i < collection.length; i++) {
collection[i].classList.toggle('hidden');
}
">toggle version 1</button>
<div class="section">
<div class="paragraph paragraph1">
Lorem Ipsum is<mark class="mark1"> <span>simply dummy text of</span></mark> the printing and typesetting industry. <mark class="mark1"><span>Lorem Ipsum</span> </mark>has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</div>
</div>
<button onclick="
const collection = document.getElementsByClassName('mark2');
for (let i = 0; i < collection.length; i++) {
collection[i].classList.toggle('hidden');
}
">toggle version 2</button>
<div class="section">
<div class="paragraph paragraph2">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the<mark class="mark2"> <span>industry's standard dummy text ever since the 1500s</span></mark>, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</div>
</div>
</body>
</html>
This code allows you to dynamically input any text, then specify the highlighted parts, and afterwards you can copy it or choose to hide or display it as you wish.
I tried to write comments for the codes.
function updateWordList() {
let text = document.getElementById('inputText').value;
let words = text.split(/\s+/);
let wordListDiv = document.getElementById('wordList');
wordListDiv.innerHTML = '';
// Create a checkbox for each word
words.forEach((word, index) => {
if (word) {
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `word-${index}`;
checkbox.value = word;
checkbox.onchange = updateHighlight;
let label = document.createElement('label');
label.htmlFor = `word-${index}`;
label.innerText = word;
wordListDiv.appendChild(checkbox);
wordListDiv.appendChild(label);
wordListDiv.appendChild(document.createElement('br'));
}
});
document.getElementById('resultText').innerText = text;
}
/**
* Updates the highlighted text based on the selected words from the word list.
* This function checks each word's checkbox, and if checked, highlights that word in the output.
*
* @function updateHighlight
*/
function updateHighlight() {
let text = document.getElementById('inputText').value;
let words = text.split(/\s+/);
let highlightedText = words.map((word, index) => {
let checkbox = document.getElementById(`word-${index}`);
if (checkbox && checkbox.checked) {
return `<span class="highlight" data-index="${index}">${word}</span>`;
} else {
return word;
}
}).join(' ');
document.getElementById('resultText').innerHTML = highlightedText;
}
/**
* Copies the currently displayed text (with or without highlights) to the clipboard.
* It extracts the plain text from the result, creates a temporary textarea,
* copies the content, and then removes the temporary element.
*
* @function copyHighlightedText
*/
function copyHighlightedText() {
let resultDiv = document.getElementById('resultText');
let tempTextarea = document.createElement('textarea');
tempTextarea.value = resultDiv.innerText;
document.body.appendChild(tempTextarea);
tempTextarea.select();
document.execCommand('copy');
document.body.removeChild(tempTextarea);
alert('متن کپی شد!');
}
/**
* Toggles the visibility of the highlighted words in the result text.
* When the words are hidden, they are removed from the display but stored in memory,
* and can be restored upon re-toggling.
*
* @function toggleHighlights
*/
let highlightsVisible = true;
let hiddenWords = [];
function toggleHighlights() {
let resultDiv = document.getElementById('resultText');
if (highlightsVisible) {
let highlightedSpans = resultDiv.querySelectorAll('.highlight');
hiddenWords = [];
highlightedSpans.forEach(span => {
let wordIndex = span.getAttribute('data-index');
hiddenWords.push({ index: wordIndex, word: span.innerText });
span.classList.add('hidden-word');
});
highlightsVisible = false;
} else {
hiddenWords.forEach(hidden => {
let span = resultDiv.querySelector(`.highlight[data-index="${hidden.index}"]`);
if (span) {
span.classList.remove('hidden-word');
}
});
highlightsVisible = true;
}
}
.highlight {
background-color: rgb(255, 238, 0);
}
.hidden-word {
display: none;
}
#inputText {
width: 36%;
border-radius: 6px;
height: 150px;
}
#copy {
width: 26%;
height: 35px;
background-color: rgb(111, 111, 253);
color: white;
border-radius: 5px;
outline: none;
border: none;
}
#copy:hover {
background-color: rgb(77, 77, 252);
cursor: pointer;
}
#showHide {
width: 10%;
height: 35px;
background-color: rgb(13, 189, 0);
color: white;
border-radius: 3px;
outline: none;
border: none;
}
#showHide:hover {
background-color: rgb(2, 148, 0);
cursor: pointer;
}
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Highlight with Word Selection</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Dynamic word highlight</h1>
<textarea id="inputText" rows="5" cols="50" placeholder="Enter your text ..." oninput="updateWordList()"></textarea>
<br><br>
<div id="wordList"></div>
<br><br>
<!-- buttons -->
<button id="copy" onclick="copyHighlightedText()">COPY Highlight Words</button>
<button id="showHide" onclick="toggleHighlights()">Show / hide words</button>
<!-- SHOW RESULT -->
<div id="resultText" style="margin-top: 20px; white-space: pre-wrap;"></div>
<!-- linked js -->
<script src="script-MSI.js"></script>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With