업데이트
2020.07.03 - innerHTML을 사용하지 않고 댓글 내용을 업데이트합니다.
단순히 텍스트밖에 적을 수 없는 티스토리 댓글에 링크, 이미지, 비디오, 유튜브 등을 추가해 화려하게 꾸미는 스크립트입니다.
HTML 수정
<s_rp_container>
바로 아래에 있는 요소에 id가 없다면 하나 추가해주세요.
방명록에도 사용하시려면 <s_guest_container>
아래에 있는 요소에 같은 id를 추가하시면 됩니다.
[##_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 : 400 px ;
max-width : 100 % ;
}
. resvid {
position : relative ;
width : 100 % ;
padding-bottom : 56.25 % ;
}
. resvid iframe {
position : absolute ;
top : 0 ;
left : 0 ;
width : 100 % ;
height : 100 % ;
}
이미지나 비디오가 댓글 창을 벗어나는 걸 방지하기 위해 최대 너비를 설정해주는 스타일과, 추가된 유튜브 비디오를 반응형으로 수정하는 스타일입니다. 필요하시면 추가해주세요.
확인
작업이 완료됐으면 댓글에 웹사이트의 주소, 혹은 이미지 / 비디오 등의 주소를 추가해보세요.
주소가 성공적으로 텍스트에서 링크 혹은 이미지 등으로 변경됐다면 댓글을 수정해보세요.
수정 후에도 해당 주소가 변경되면 끝입니다!
ⓒ 2020. Marshall K All rights reserved