[티스토리] 댓글에 링크 및 이미지 추가하기

개발

[티스토리] 댓글에 링크 및 이미지 추가하기
최종 수정일:

업데이트

2020.07.03 - innerHTML을 사용하지 않고 댓글 내용을 업데이트합니다.


단순히 텍스트밖에 적을 수 없는 티스토리 댓글에 링크, 이미지, 비디오, 유튜브 등을 추가해 화려하게 꾸미는 스크립트입니다.

HTML 수정

comment list

<s_rp_container> 바로 아래에 있는 요소에 id가 없다면 하나 추가해주세요.
방명록에도 사용하시려면 <s_guest_container> 아래에 있는 요소에 같은 id를 추가하시면 됩니다.

comment text

[##_rp_rep_desc_##]을 감싼 요소에 class가 없다면 하나 추가해주세요. 댓글용과 답글용 2개가 있을 겁니다. 혹 class가 있더라도 해당 치환자를 감싼 요소가 아닌 다른 곳에도 사용되었다면 별도로 하나 추가해주세요.
마찬가지로 방명록에도 사용하시려면 [##_guest_rep_desc_##]를 검색하셔서 같은 작업을 진행하시면 됩니다.

Javascript 작업

const autoWrap = (containerId, selector) => {
  const wrapping = async () => {
    const link = /(\b(https?|ftp|file):\/\/[-A-Z0-9|ㄱ-ㅎ|ㅏ-ㅣ|가-힣|+&@#\/%?=~_|!:,.;]*[-A-Z0-9|ㄱ-ㅎ|ㅏ-ㅣ|가-힣|+&@#\/%=~_|])/gi; // 링크 찾기
    const mail = /((\S+.)@[a-z]+.[a-z]+)/gi;
    const imageType = /\.(?:jpe?g(:(large|orig))?|gif|png(:(large|orig))?|svg)$/i; // 이미지
    const TistoryImage = /(?:\?original)$/i; // 티스토리 ?original 이미지
    const videoType = /\.(?:mp4|webm)$/i; // 비디오
    const audioType = /\.(?:mp3|ogg|wav)$/i; // 오디오
    const youtubeLink = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?/g; // 유튜브 비디오
    const createAnchor = (string, type = "link") => {
      const anchor = document.createElement("a");
 
      anchor.href = type === "link" ? string : `mailto:${string}`;
      type === "link" &&
        ((anchor.target = "_blank"),
        anchor.setAttribute("rel", "noopener, noreferrer"));
      anchor.innerText = string;
 
      return anchor;
    };
 
    document.querySelectorAll(selector).forEach((comment) => {
      !comment.classList.contains("modded") &&
        comment.hasChildNodes &&
        [...comment.childNodes].forEach((text) => {
          if (text.nodeType === 3) {
            let textArray = text.textContent.split(link);
            if (textArray.length === 1)
              textArray = text.textContent.split(mail);
            if (textArray.length === 1) return;
            const fragment = document.createDocumentFragment();
 
            for (
              let i = 0, length = textArray.length, j = 1;
              i < length;
              i++
            ) {
              if (j % 3 !== 0) {
                const string = textArray[i];
                if (j % 2 === 0) {
                  if (string.includes("http:")) {
                    const anchor = createAnchor(string);
 
                    fragment.append(anchor);
                  } else {
                    if (
                      imageType.test(string) ||
                      TistoryImage.test(string)
                    ) {
                      const img = document.createElement(
                        "img"
                      );
 
                      img.src = string;
                      img.alt = "userContent";
 
                      fragment.append(img);
                    } else if (videoType.test(string)) {
                      const video = document.createElement(
                        "video"
                      );
 
                      video.src = string;
                      video.autoplay = 1;
                      video.muted = 1;
                      video.loop = 1;
                      video.setAttribute(
                        "playsinline",
                        1
                      );
 
                      fragment.append(video);
                    } else if (audioType.test(string)) {
                      const audio = document.createElement(
                        "audio"
                      );
 
                      audio.src = string;
                      audio.controls = 1;
 
                      fragment.append(audio);
                    } else if (youtubeLink.test(string)) {
                      const wrapper = document.createElement(
                        "div"
                      );
                      const div = document.createElement(
                        "div"
                      );
                      const iframe = document.createElement(
                        "iframe"
                      );
 
                      wrapper.className =
                        "youtubevid-wrapper";
                      div.className = "resvid";
 
                      iframe.src = `https://www.youtube.com/embed/${string.replace(
                        youtubeLink,
                        ""
                      )}?rel=0&playsinline=1`;
                      iframe.allowFullscreen = 1;
                      iframe.frameBorder = 0;
 
                      div.append(iframe);
                      wrapper.append(div);
                      fragment.append(wrapper);
                    } else if (mail.test(string)) {
                      const anchor = createAnchor(
                        string,
                        "mail"
                      );
 
                      fragment.append(anchor);
                    } else {
                      const anchor = createAnchor(string);
 
                      fragment.append(anchor);
                    }
                  }
                } else {
                  const textNode = document.createTextNode(
                    string
                  );
 
                  fragment.append(textNode);
                }
 
                j += 1;
              } else {
                j = 1;
              }
            }
 
            text.parentNode.insertBefore(fragment, text);
            text.remove();
          }
 
          comment.classList.add("modded");
        });
    });
  };
 
  document.addEventListener(
    "DOMContentLoaded",
    wrapping().then(() => {
      // 수정, 삭제, 이전 댓글 불러오기 등 변화 감지
      const container = document.getElementById(containerId);
      const observer = new MutationObserver(wrapping);
 
      container &&
        observer.observe(container, {
          attributes: true,
          childList: true,
          subtree: true,
        });
    })
  );
};

예전 스크립트는 0.5초마다 한 번씩 함수를 실행하게 해뒀는데, 이젠 MutationObserver를 이용해 변화를 감지하게 해뒀습니다.

위 스크립트를 별도로 js 파일로 작성해 스킨 편집에서 업로드하셔서 사용하시거나, 아래 주소를 사용하시면 업로드 필요 없이 압축된 js 파일을 사용하실 수 있습니다.

jsdelivr : https://cdn.jsdelivr.net/gh/marshall-ku/update-tistory-comments@latest/dist/autoWrap.js
github : https://marshall-ku.github.io/update-tistory-comments/dist/autoWrap.js

autoWrap("comment-list", ".comment-text");

스크립트 추가를 완료하셨다면, 위 코드처럼 호출해주세요.
첫 번째 인자론 <s_rp_container> 바로 아래에 있는 요소에 추가한 id를, 두 번째 인자론 [##_rp_rep_desc_##]를 감싼 요소에 추가한 class를 .과 함께 입력해주세요.

CSS 작업 (선택)

/* 이미지 비디오 최대 너비 설정 */
img,
video {
    max-width: 100%;
}
 
/* 유튜브 비디오 반응형으로 수정 */
.youtubevid-wrapper {
    width: 400px;
    max-width: 100%;
}
 
.resvid {
    position: relative;
    width: 100%;
    padding-bottom: 56.25%;
}
 
.resvid iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

이미지나 비디오가 댓글 창을 벗어나는 걸 방지하기 위해 최대 너비를 설정해주는 스타일과, 추가된 유튜브 비디오를 반응형으로 수정하는 스타일입니다. 필요하시면 추가해주세요.

확인

이미지 추가된 댓글

작업이 완료됐으면 댓글에 웹사이트의 주소, 혹은 이미지 / 비디오 등의 주소를 추가해보세요.

수정된 댓글

주소가 성공적으로 텍스트에서 링크 혹은 이미지 등으로 변경됐다면 댓글을 수정해보세요.
수정 후에도 해당 주소가 변경되면 끝입니다!

Report an issue