This page is a sample program that searches for text in a specific specified portion of a web page. The matched text is highlighted and you are directed to that text.
Once you confirm the keyword input, you will be directed to the matched text. If there are multiple matched texts, press the "Enter" key to move to the next text. Please copy "css", "JavaScript", etc. and use them.
<!-- CSS Section Start -->
<!-- ハイライトのCSS - 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 = []; // ハイライトされた要素を格納する配列
let currentIndex = -1; // 現在のハイライト位置を示すインデックス
let lastSearchTerm = ''; // 最後に検索された語句を保持する変数
let searchTimer = null; // 入力変更後に検索を遅延させるためのタイマー
let isComposing = false; // 入力中の状態を保持
let caseSensitive = false; // 大文字小文字の区別フラグ(デフォルトは区別しない)
/**
* 特殊文字をエスケープする関数
* @param {string} string - エスケープする文字列
* @returns {string} - エスケープされた文字列
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* 検索を実行し、マッチしたテキストをハイライトする関数
* @param {string} searchTerm - 検索語
*/
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();
}
/**
* テキストノード内で検索語を見つけてハイライトする関数
* @param {Node} element - 検索対象のノード
* @param {string} searchTerm - 検索語
*/
function searchAndHighlight(element, searchTerm) {
if (element.nodeType === 3) { // テキストノード
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));
}
}
/**
* 現在のハイライト要素にスクロールする関数
* @param {number} index - ハイライト要素のインデックス
*/
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 nextHighlight() {
if (highlights.length > 0) {
currentIndex = (currentIndex + 1) % highlights.length;
scrollToHighlight(currentIndex);
}
}
/**
* 前のハイライトに移動する関数
*/
function previousHighlight() {
if (highlights.length > 0) {
currentIndex = (currentIndex - 1 + highlights.length) % highlights.length;
scrollToHighlight(currentIndex);
}
}
/**
* ハイライトをリセットする関数
*/
function resetHighlights() {
highlights.forEach(el => {
el.outerHTML = el.innerHTML;
});
highlights = [];
currentIndex = -1;
lastSearchTerm = '';
}
/**
* 検索をリセットし、入力枠にスクロールする関数
*/
function resetSearch() {
resetHighlights();
document.getElementById('searchTerm').value = '';
scrollToSearchInput();
}
/**
* 入力枠にスクロールする関数
*/
function scrollToSearchInput() {
const searchInput = document.getElementById('searchTerm');
searchInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
searchInput.focus(); // 入力枠にフォーカスも合わせる
}
/**
* 検索の処理を実行する関数
*/
function handleSearch() {
const searchTerm = document.getElementById('searchTerm').value;
// 検索語句が空の場合にリセットし、入力枠にスクロールする
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 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キーを押します">
<button onclick="nextHighlight()">次へ Next</button> <button onclick="previousHighlight()">前へ Previous</button> <button onclick="resetSearch()">リセット Reset</button>
<!-- 大文字小文字の区別を選択するラジオボタンを設置 -->
<!-- 必要がなければ非表示に。非表示にした場合「区別しない」がデフォルト -->
<div>
大文字[A]・小文字[a]を <label><input type="radio" name="caseOption" value="insensitive" checked>区別しない</label> <label><input type="radio" name="caseOption" value="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 -->