*The following text is a sample search target.*
- You can test the program's functionality using the text within this frame.
- This page is a sample program for searching a specific part of a webpage's text. It highlights the matched text and scrolls to it.
- Once a search term is entered, the page scrolls to the matched text.
- If multiple pieces of text are highlighted, press Enter to scroll to the next.
- You can copy and use the CSS or JavaScript as needed.
Try entering the characters above or below.
*This is the end of the sample search text.*
<!-- CSS Section Start -->
<!-- CSS for Highlight -->
<style>
.highlight {
font-weight: bold;
color: #333333;
background-color: Yellow;
padding: 3px 5px;
}
.current {
outline: 2px solid crimson;
}
</style>
<!-- CSS for Buttons and other decorations -->
<style>
/* Input Field Styles */
input[type="text"] {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
width: 300px;
box-sizing: border-box;
margin-right: 10px;
transition: all 0.3s ease;
}
input[type="text"]:focus {
border-color: #007bff;
box-shadow: 0 0 8px rgba(0, 123, 255, 0.2);
outline: none;
}
/* Button Style */
button {
padding: 10px 15px;
border: 1px solid #007bff;
background-color: #007bff;
color: #fff;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s ease;
margin-right: 5px;
}
button:hover {
background-color: #0056b3;
}
button:focus {
outline: none;
box-shadow: 0 0 8px rgba(0, 123, 255, 0.3);
}
/* Radio Button Style */
.case-sensitivity {
margin-top: 15px;
font-size: 14px;
}
.case-sensitivity label {
margin-right: 15px;
font-weight: normal;
}
.case-sensitivity input[type="radio"] {
margin-right: 5px;
}
/* Mobile-friendly design */
@media (max-width: 480px) {
input[type="text"] {
width: 100%;
margin-bottom: 10px;
}
button {
width: 100%;
margin-bottom: 10px;
}
.case-sensitivity {
text-align: left;
}
}
</style>
<!-- CSS Section End -->
<!-- JavaScript Section Start -->
<script>
let highlights = []; // Array to store highlighted elements
let currentIndex = -1; // Index of the current highlight position
let lastSearchTerm = ''; // Variable to store the last searched term
let searchTimer = null; // Timer to delay search after input changes
let isComposing = false; // Variable to track input composition state
let caseSensitive = false; // Flag for case sensitivity (default is insensitive)
/**
* Function to escape special characters in a string
* @param {string} string - The string to be escaped
* @returns {string} - The escaped string
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* Function to execute the search and highlight matching text
* @param {string} searchTerm - The search term
*/
function search(searchTerm) {
if (!searchTerm || searchTerm === lastSearchTerm) return;
lastSearchTerm = searchTerm;
resetHighlights();
searchTerm = escapeRegExp(searchTerm);
const content = document.getElementById('content_to_search');
searchAndHighlight(content, searchTerm);
if (highlights.length > 0) {
currentIndex = 0;
scrollToHighlight(currentIndex);
}
document.getElementById('searchTerm').focus();
}
/**
* Function to find and highlight matching text within a text node
* @param {Node} element - The node to search within
* @param {string} searchTerm - The search term
*/
function searchAndHighlight(element, searchTerm) {
if (element.nodeType === 3) { // Text node
const regex = new RegExp(searchTerm, caseSensitive ? 'g' : 'gi');
const matches = element.textContent.match(regex);
if (matches) {
const parent = element.parentNode;
const fragment = document.createDocumentFragment();
let lastIndex = 0;
matches.forEach(match => {
const matchStart = element.textContent.indexOf(match, lastIndex);
const matchEnd = matchStart + match.length;
fragment.appendChild(document.createTextNode(element.textContent.slice(lastIndex, matchStart)));
const span = document.createElement('span');
span.className = 'highlight';
span.textContent = match;
fragment.appendChild(span);
lastIndex = matchEnd;
highlights.push(span);
});
fragment.appendChild(document.createTextNode(element.textContent.slice(lastIndex)));
parent.replaceChild(fragment, element);
}
} else {
Array.from(element.childNodes).forEach(child => searchAndHighlight(child, searchTerm));
}
}
/**
* Function to scroll to the current highlight element
* @param {number} index - The index of the highlight element
*/
function scrollToHighlight(index) {
if (highlights.length > 0) {
highlights.forEach(el => el.classList.remove('current'));
highlights[index].classList.add('current');
highlights[index].scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
/**
* Function to move to the next highlight
*/
function nextHighlight() {
if (highlights.length > 0) {
currentIndex = (currentIndex + 1) % highlights.length;
scrollToHighlight(currentIndex);
}
}
/**
* Function to move to the previous highlight
*/
function previousHighlight() {
if (highlights.length > 0) {
currentIndex = (currentIndex - 1 + highlights.length) % highlights.length;
scrollToHighlight(currentIndex);
}
}
/**
* Function to reset all highlights
*/
function resetHighlights() {
highlights.forEach(el => {
el.outerHTML = el.innerHTML;
});
highlights = [];
currentIndex = -1;
lastSearchTerm = '';
}
/**
* Function to reset the search and scroll to the input field
*/
function resetSearch() {
resetHighlights();
document.getElementById('searchTerm').value = '';
scrollToSearchInput();
}
/**
* Function to scroll to the search input field
*/
function scrollToSearchInput() {
const searchInput = document.getElementById('searchTerm');
searchInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
searchInput.focus(); // Also focus on the input field
}
/**
* Function to handle the search process
*/
function handleSearch() {
const searchTerm = document.getElementById('searchTerm').value;
// Reset and scroll to input field if search term is empty
if (searchTerm === '') {
resetSearch();
return;
}
if (searchTerm && searchTerm !== lastSearchTerm) {
search(searchTerm);
if (highlights.length === 0) {
scrollToSearchInput();
}
}
}
document.getElementById('searchTerm').addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
const searchTerm = this.value;
if (searchTerm) {
if (currentIndex === -1) {
handleSearch();
} else {
nextHighlight();
}
}
}
});
document.getElementById('searchTerm').addEventListener('input', function() {
if (searchTimer) clearTimeout(searchTimer);
if (!isComposing) {
searchTimer = setTimeout(handleSearch, 500);
}
});
document.getElementById('searchTerm').addEventListener('compositionstart', function() {
isComposing = true;
});
document.getElementById('searchTerm').addEventListener('compositionend', function() {
isComposing = false;
handleSearch();
});
document.querySelectorAll('input[name="caseOption"]').forEach(radio => {
radio.addEventListener('change', handleCaseOptionChange);
});
/**
* Function to handle changes in case sensitivity setting
*/
function handleCaseOptionChange() {
caseSensitive = document.querySelector('input[name="caseOption"]:checked').value === 'sensitive';
search(document.getElementById('searchTerm').value);
}
</script>
<!-- JavaScript Section End -->
<!-- HTML Section Start -->
<input type="text" id="searchTerm" placeholder="Enter search term and press Enter">
<button onclick="nextHighlight()">Next</button> <button onclick="previousHighlight()">Previous</button> <button onclick="resetSearch()">Reset</button>
<!-- Radio buttons to select case sensitivity -->
<!-- Hide if not needed; default is case insensitive -->
<div>
Case sensitivity: <label><input type="radio" name="caseOption" value="insensitive" checked>Insensitive</label> <label><input type="radio" name="caseOption" value="sensitive">Sensitive</label>
</div>
<!-- Highlight target range - start -->
<div id="content_to_search">
Body text to search for
</div>
<!-- Highlight target range - end -->
<!-- HTML Section End -->