업무 기록/WEB

자바스크립트 마크다운 검색창 만들기

code2772 2023. 9. 8. 06:46
728x90
반응형

#in 에 마크다운을 작성하게 되면 #out에 htm로 자동 변환되는 상황에서 검색창을 입력하여 내가 원하는 단어를 찾는 간단한 Javascript이용하여 쉽게 만들 수 있을거라고 생각하였다. 하지만 만들면서 여러 문제점이 발생하였다. 화면에 표출되는 #out 부분의 제목 부분이 #, ##, ### 과 같이 해시를 사용하여 이상한 반복이 발생하는 경우도 있고 또는 #out 부분이 없어지거나 #in 마크다운 내용으로 바뀌는 경우등 많은 문제점들이 발생하였다.
 

기본 HTML 틀

<div id="in">
    <form>
        <textarea id="code" contenteditable="true">
# News Title 1
## Subheading 1
### Subheading 1.1
# Another topic
        </textarea>
    </form>
</div>
<div id="out" class="markdown-body"></div>
<div id="tree"></div>
<div id="search-box">
      <input type="text" id="search-input" placeholder="Search">
  </div>

이전 자동 목록 만들기와 구조는 유사하다.
 

전체코드

<div id="in">
    <form>
        <textarea id="code" contenteditable="true">
# News Title 1
## Subheading 1
### Subheading 1.1
# Another topic
        </textarea>
    </form>
</div>
<div id="out" class="markdown-body"></div>
<div id="tree"></div>

<script>
    // Markdown을 HTML로 변환하는 함수
    function convertMarkdownToHTML() {
        var markdownText = document.getElementById('code').value;
        var converter = new showdown.Converter();
        var htmlText = converter.makeHtml(markdownText);
        return htmlText;
    }

    // #in의 textarea 내용이 변경될 때마다 호출
    document.getElementById('code').addEventListener('input', function () {
        var htmlText = convertMarkdownToHTML();
        document.getElementById('out').innerHTML = htmlText;
    });

    var lastSearchQuery = '';
    var lastMatchedIndices = [];
    var currentIndex = -1;

    function clearHighlight() {
        var outputDiv = document.getElementById('out');
        var highlightedHTML = outputDiv.innerHTML;
        highlightedHTML = highlightedHTML.replace(/<mark class="highlight">([^<]+)<\/mark>/gi, '$1');
        outputDiv.innerHTML = highlightedHTML;
    }

    function searchAndHighlight() {
        var query = document.getElementById('search-input').value;
        var outputDiv = document.getElementById('out');
        var textToSearch = outputDiv.innerText; // HTML 태그를 제외한 텍스트만 검색
        var regex = new RegExp(query, 'gi');
        var matches = Array.from(textToSearch.matchAll(regex));

        // 검색을 시작할 때 이전에 강조된 부분을 초기화
        clearHighlight();

        // 검색 결과 저장
        lastMatchedIndices = matches.map(function (match) {
            return match.index;
        });

        // 다음 일치 항목 찾기
        currentIndex = (currentIndex + 1) % lastMatchedIndices.length;
        var nextIndex = lastMatchedIndices[currentIndex];

        // 일치 항목을 강조 표시
        var highlightedHTML = outputDiv.innerHTML;
        if (nextIndex !== undefined) {
            var matchText = matches[currentIndex][0];
            highlightedHTML = highlightedHTML.replace(
                new RegExp('(' + matchText + ')(?![^<]*>)', 'gi'),
                '<mark class="highlight">$1</mark>'
            );

            // 스크롤 위치 조정
            var newScrollPosition = nextIndex;
            outputDiv.scrollTop = newScrollPosition;
        }
        outputDiv.innerHTML = highlightedHTML;
    }

    document.getElementById('search-input').addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
            event.preventDefault();
            searchAndHighlight();
        }
    });

    // 초기에 Markdown을 HTML로 변환하여 #out에 표시
    var initialHTML = convertMarkdownToHTML();
    document.getElementById('out').innerHTML = initialHTML;
</script>

ctrl + f 키랑 기능은 동일하다

 
 

세부코드 설명

Markdown을 HTML로 변환하는 함수:

// Markdown을 HTML로 변환하는 함수
function convertMarkdownToHTML() {
    var markdownText = document.getElementById('code').value;
    var converter = new showdown.Converter();
    var htmlText = converter.makeHtml(markdownText);
    return htmlText;
}

이 함수는 showdown 라이브러리를 사용하여 Markdown 형식의 텍스트를 HTML로 변환한다.
#code 요소의 값을 가져와 Markdown을 HTML로 변환하고 결과를 반환한다.
 

Markdown 입력 내용이 변경될 때 HTML 업데이트:

// #in의 textarea 내용이 변경될 때마다 호출
document.getElementById('code').addEventListener('input', function () {
    var htmlText = convertMarkdownToHTML();
    document.getElementById('out').innerHTML = htmlText;
});

#code 요소의 내용이 변경되면, convertMarkdownToHTML 함수를 호출하여 Markdown을 HTML로 변환하고, 변환된 HTML을 #out 요소에 업데이트한다.
 

검색 및 강조 표시 기능:

var lastSearchQuery = '';
var lastMatchedIndices = [];
var currentIndex = -1;

// ...

function searchAndHighlight() {
    // ...

    // 검색을 시작할 때 이전에 강조된 부분을 초기화
    clearHighlight();

    // 검색 결과 저장
    lastMatchedIndices = matches.map(function (match) {
        return match.index;
    });

    // ...

    // 일치 항목을 강조 표시
    var highlightedHTML = outputDiv.innerHTML;
    if (nextIndex !== undefined) {
        // ...
    }
    outputDiv.innerHTML = highlightedHTML;
}

// ...

// 검색 입력 필드에서 Enter 키를 누를 때 처리
document.getElementById('search-input').addEventListener('keydown', function (event) {
    if (event.key === 'Enter') {
        event.preventDefault();
        searchAndHighlight();
    }
});

이 부분은 사용자가 검색어를 입력하고 Enter 키를 누를 때 검색 및 강조 표시를 수행하는 기능이다.
clearHighlight 함수를 사용하여 이전에 강조된 부분을 제거.
검색 결과를 찾고, 일치하는 항목을 강조 표시한다.
검색 결과는 lastSearchQuery, lastMatchedIndices, currentIndex 변수를 사용하여 관리된다.
 

초기 변환 및 HTML 출력

// 초기에 Markdown을 HTML로 변환하여 #out에 표시
var initialHTML = convertMarkdownToHTML();
document.getElementById('out').innerHTML = initialHTML;

페이지가 로드될 때 초기 Markdown을 HTML로 변환하고, 변환된 HTML을 #out 요소에 출력한다.
 
 
솔직히 그냥 구글에 돌아다니는 코드 복붙하면 10분이면 끝나겠다고 생각하였지만 바로 내용을 찾는게 아닌 숨겨진? 내용이나 좀 얽힌 내용이 많아 너무 많은 삽질을하였다....

반응형