본문 바로가기
웹 코딩/티스토리

댓글 (+방명록) - URL 처리 (링크 및 이미지 적용)

by 알릭2 2020. 9. 7.

댓글에 주소와 이미지 정도는 허용하자구요 ㅋ

 

역시나 제가 필요해서 만들게 된 아이입니다...ㅋ

주요 기능

  • 댓글에 URL 주소가 입력된 경우, 클릭하면 새창이 열리게 만들어 줍니다.
    • 실제 a 태그로 변환하는건 아니고 onclick 으로 안전하게 처리합니다.
  • URL 주소가 이미지라면 해당 텍스트를 없애고 이미지를 바로 보여줍니다.
    • 이미지를 불러오는데 문제가 생기면 그냥 url을 유지합니다.
    • data:image 형식의 data URL도 이미지로 바꿔줍니다.
    • 이미지 클릭 시 새창을 통해 이미지로 이동합니다.
  • 방명록도 댓글이라 원하실 경우 동일하게 처리할 수 있습니다.
  • 댓글/방명록의 신규 등록 및 수정시 모두 바로 바로 처리됩니다.

적용 방법

1. 스킨 html 수정

<p><span class="rp_text"></span><br>
<a href="#" onclick="" class="reply">답글</a></p>
...
...
...
</div>
<p><span class="rp_text"></span></p>
</li>
...
...
...
</div>
<p><span class="rp_text"></span><br>
<a href="#" class="reply" onclick="">답변</a></p>
...
...
...
</div>
<p><span class="rp_text"></span></p>
</li>

위 코드와 같이 댓글의 내용이 보여지는 를 찾아 각각 <span class="rp_text">  ... </span> 으로 감싸줍니다.

(만일 방명록에는 적용하고 싶지 않다면 는 건너띄시면 됩니다.)

 

2. 스타일 추가

(스킨 css건 html이건 어디든 편한 곳에)

.rp_text, .rp_url {
  word-break: break-all;
}
.rp_url:hover {
  background: lavender;
  text-decoration: underline;
  cursor: pointer;
}
.rp_img {
  display: none;
  max-width: 95%;
  max-height: 600px;
  margin: 10px 0;
  cursor: pointer;
}

주소에 마우스오버시 변하는 색상이나 이미지 최대 크기 및 간격(margin)등을 조정하실 수 있습니다.

display: none; 과 word-break: break-all; 은 유지해 주세요.

 

3. 스크립트 추가

 

늘 그렇듯 스킨 html 수정을 통해서 </body>위에 <script> ... </script> 로 잘 감싸서 넣어주셔도 되고 파일로 업로드해서 적용하셔도 됩니다.

!function(){
	if (document.querySelector('#entry0Comment')) {
		var commentWrapper = document.querySelector('#content'); 
	} else {
		var commentWrapper = document.querySelector('.comments');	
	}
	if (!commentWrapper) { return; }
	prep_rp(commentWrapper);
	commentWrapper.addEventListener('DOMNodeInserted', function(event) {
		if (event.target.nodeType == 1 && event.target.querySelector('.rp_text')) {
			prep_rp(event.target);
		}
	});
}();

function prep_rp(comms) {
	if (!comms || comms.querySelector('.rp_url')) { return; }
	var rps = comms.querySelectorAll('.rp_text');
	for (var i = 0; i < rps.length; i++) {
		var matches, emoticons = {}, pluginUsed = false;
		var rp = rps[i];
		var rpText = rp.innerHTML;
		var regex = new RegExp(/(?:[="']*)(?:(?:data:image\/)|(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’\u3131-\uD79D]))?/, 'gi');
		if (regex.test(rpText)) {
			rpText = rpText.replace(/<img[^<]+EmoticonOnComment.+?alt=\"(.+?)\"[\s\/]*>/gi, function(match, $1) {
				if ($1.length) {
					pluginUsed = true;
					emoticons[$1] = match; 
					return $1;
				} else {
					return match;
				}
			});
			rpText = rpText.replace(regex, function(url) {
				var firstChar = url.slice(0,1);
				if (firstChar == '=') {
					return url;
				} else {
					return '<span title="새창으로 열기" class="rp_url">' + url + '</span>';
				}
			});
			rp.innerHTML = rpText;
			if (pluginUsed) {
				var nodes = rp.childNodes;
				for (var ii = 0; ii < nodes.length; ii++) {
					var node = nodes[ii];
					if (node.nodeType === 3) {
						var spanNode = document.createElement('span');
						var text = node.textContent;
						for (var iii in emoticons) {
							 text = text.replace(new RegExp(iii.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), 'g'), emoticons[iii]);
						}
						spanNode.innerHTML = text;
						node.parentNode.replaceChild(spanNode, node);
					}
				}
			}	
			event_rp(rp);
		}		
	}
}

function event_rp(rp) {
	var urls = rp.querySelectorAll('.rp_url');
	for (var i = 0; i < urls.length; i++) {
		var url = urls[i];
		var urlText = url.innerText;
		url.addEventListener("click", function() {
			var newUrl = this.innerText;
			if (newUrl.slice(0,8).indexOf('//') < 0) {
				newUrl = '//'+newUrl;
			}
			window.open(newUrl);
		});
		if (/(?:(?:data\:image)|(?:(?:img|images?|thumbn?a?i?l?s?|photo|pic)\/[^\s]*?)|(?:\/[^\s]+?\.(?:png|jpe?g|gif|ico|svg|tif{1,2})))/i.test(urlText)) {
			var img = new Image();
			url.parentNode.insertBefore(img, url);
			img.src = urlText;
			img.className = 'rp_img';
			img.title = '새창으로 열기';
			img.onload = function() {
				this.parentNode.removeChild(this.nextElementSibling);
				if (this.nextElementSibling && this.nextElementSibling.tagName == 'BR') {
					this.parentNode.removeChild(this.nextElementSibling);
				}
				this.style.display = 'block';
			};
			img.onclick = function() {
				if (this.src.slice(0,8).indexOf('//') < 0) {
					var win = window.open("", "image");
					win.document.body.style.margin = '0';
					win.document.body.innerHTML = '<iframe width="100%" height="100%" border="0" style="border:0;" src="'+this.src+'"></iframe>';
				} else {
					window.open(this.src);
				}
			}
		}
	}
}

참고할 점은, 위 코드 3, 5번줄에 '#content''.comments' 인데요. .comments 는 자신의 스킨에서 <s_rp> 보다 위에 나오는 댓글을 감싸는 영역의 클래스 값이나 id 값을 찾아 넣어주셔야 하고, #content 는 .comments 보다 더 상위에서 #entry0Comment 를 감싸는 본문 전체 영역의 ID입니다. (class는 . 으로 id는 # 으로 시작) 

 

아래는 북클럽 스킨 기준 예시입니다.

</s_article_related>
<div class="comments">
	<h2>댓글<span class="count"><s_rp_count>5</s_rp_count></span></h2>
	<s_rp>
		<s_rp_container>

브라우저 개발자도구 (F12)로 보면 나와요

 

추가

 

혹여 [댓글/방명록 이모티콘 표시] 플러그인을 사용중이라도 전혀 문제 없습니다.

 

 

- 끝 - 

 

 

문의사항이나 건의사항은 언제나 환영이니 댓글로 남겨주세요. ^^

댓글