大文字[A]・小文字[a]を(Case sensitivity:)
 



《 CSS JavaScript HTML 》
Click to copy
    <!-- 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 -->