Wap4: Hàm commentSection

By Asuna, 2925 View
Demo:https://dorew.gq
Edited by @Dai & @Asuna
Lưu ý: Chỉnh sửa lại các hàm tương ứng được sử dụng trong hàm commentSecrion sao cho phù hợp với web của bạn.

I) Hàm commentSection
Thêm hàm commentSection vào tệp chứa các macro của web bạn. Ví dụ: _cmS.twig.
{% macro commentSection(postUrl) %}
{% from 'func.twig' import login,get,add,maunick,getAvtUser,rwurl %}
{% import 'func.twig' as func %}
{% set login = login()|trim %}
{% set url=get_uri_segments() %}
{% set user = get_data('user_'~login)|last.data|json_decode %}
{% set commentRead = 'url lấy ở bước 6' %}
{% set commentPost = 'url lấy ở bước 4' %}
{% set commentPostUrl = 'entry article url' %}
{% set commentPostUsername = 'entry name' %}
{% set commentPostComment = 'entry comment' %}

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
 integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-csv/1.0.11/jquery.csv.min.js"
 integrity="sha512-Y8iWYJDo6HiTo5xtml1g4QqHtl/PO1w+dmUpQfQSOTqKNsMhExfyPN2ncNAe9JuJUSKzwK/b6oaNPop4MXzkwg=="
 crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/validator/13.1.1/validator.min.js"
 integrity="sha512-rVYlbsnsxljzvf4sgKzI6ncbNKKxupFhoQ/9ptW7R5fhKE9wQevsfUAZEbJ6xl+VyaiGm3lAKChPLoV/VuaZJA=="
 crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-linkify/2.1.9/linkify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-linkify/2.1.9/linkify-jquery.min.js"></script>
<script src="https://marcusvi200.github.io/list-array/script/ListArray.js"></script>

<script src="/js/marked-Ext.js"></script>



<script>
var thisPageUrl="{{ postUrl }}",visibleComments=[];function formatDate(r){var e=new Date(r);return`${e.toLocaleDateString("vi",{year:"numeric",month:"numeric",day:"numeric"})} ${e.toLocaleTimeString("vi",{hour:"numeric",minute:"numeric"})}`}function getQueryVariable(r){for(var e=window.location.search.substring(1).split("&"),t=0;t<e.length;t++){var i=e[t].split("=");if(i[0]==r)return i[1]}return!1}var listArray=new ListArray;
{% set data=[] %}{% set play='yes' %}{% for i in 1..100 %}{% if play=='yes' %}{% set data2=get_data( 'id_users',50,i) %}{% endif %}{% if data2 %}{% set data=data2|reverse|merge(data) %}{% else %}{% set play='no' %}{% set data2='' %}{% endif %}{% endfor %}{% set total=data|length %}{% set entries= data|reverse %}{% set entries = entries%}{% set data='' %}{% if total == 0 %}{% endif %}{% set demA = 0 %}
{% for i in entries %}{% set thanhvien = i.data %}let element{{demA}} = {nick: '{{thanhvien}}', name: '{{get('user_'~thanhvien,'nick')}}', avatar_link: '{{getAvtUser(thanhvien)|trim}}'};listArray.push(element{{demA}});{% set demA = demA + 1 %}{% endfor %}

function displayComments(n){if(null!=n&&""!==n){n=`timestamp,name,comment,isAuthor
${n}`,commentList=$.csv.toObjects(n),console.log("Tong comment"+commentList.length);var e=1;getQueryVariable("page")&&(e=getQueryVariable("page")),commentList.reverse(),console.log("Page hien tai = "+e);var a,t=7*(e-1),o=7*e-1,s=t;console.log("Dau "+t),console.log("Cuoi"+o);var m=1;m=commentList.length%7>0?Math.floor(commentList.length/7)+1:Math.floor(commentList.length/7),console.log("Tong page "+m),$("#phan-trang").empty();var l=e-1,c=e-2,p=Number(e)+1,i=Number(e)+2;for(e>1&&$("#phan-trang").append('<a class="pagenav" href="?page='+l+'">«</a>'),e>3&&$("#phan-trang").append('<a class="pagenav" href="?page=1">1</a>'),e>4&&$("#phan-trang").append("..."),e>2&&$("#phan-trang").append('<a class="pagenav" href="?page='+c+'">'+c+"</a>"),e>1&&$("#phan-trang").append('<a class="pagenav" href="?page='+l+'">'+l+"</a>"),$("#phan-trang").append('<span class="current"><b>'+e+"</b></span>"),e<m-1&&$("#phan-trang").append('<a class="pagenav" href="?page='+p+'">'+p+"</a>"),e<m-2&&$("#phan-trang").append('<a class="pagenav" href="?page='+i+'">'+i+"</a>"),e<m-3&&$("#phan-trang").append("..."),e<m&&$("#phan-trang").append('<a class="pagenav" href="?page='+m+'">'+m+"</a>"),e<m&&$("#phan-trang").append('<a class="pagenav" href="?page='+p+'">»</a>'),a=t;a<=o;a++){if(s>=commentList.length){console.log("Load xong, id cuoi "+s);break}if(s++,visibleComments.includes(JSON.stringify(commentList[a])))return;var r=validator.escape(commentList[a].name),g=listArray.find(n=>n.nick===r),h=$(`





<div class="list1 comment-item"><table cellpadding="0" cellspacing="1"><tbody><tr><td width="auto"><img class="imgAvtUser" src="${g.value.avatar_link}" width="60" height="60"></td><td><a href="/user/${r}"><b><font color="DarkSlateGrey">${g.value.name}</font></b></a><br><small><font color="#999"><i class="fa fa-clock-o"></i> ${formatDate(commentList[a].timestamp)}</font></small></td></tr></tbody></table><div class="chatbox"> <span class="textchat"> </span>${marked(validator.escape(commentList[a].comment))}</div>
</div>







 		`).hide();$("#commentSection").append(h),h.fadeIn(),visibleComments.push(JSON.stringify(commentList[a])),$(".comment-item").linkify(),$("#no-comments").hide()}}else 0==visibleComments.length&&$("#no-comments").show()}function displayNewComments(n){if(null!=n&&""!==n){n=`timestamp,name,comment,isAuthor
${n}`,commentList=$.csv.toObjects(n),console.log("Tong comment"+commentList.length);var e=1;getQueryVariable("page")&&(e=getQueryVariable("page")),commentList.reverse(),console.log("Page hien tai = "+e);var a,t=7*(e-1),o=7*e-1,s=t;console.log("Dau "+t),console.log("Cuoi"+o);var m=1;m=commentList.length%7>0?Math.floor(commentList.length/7)+1:Math.floor(commentList.length/7),console.log("Tong page "+m),$("#phan-trang").empty();var l=e-1,c=e-2,p=Number(e)+1,i=Number(e)+2;for(e>1&&$("#phan-trang").append('<a class="pagenav" href="?page='+l+'">«</a>'),e>3&&$("#phan-trang").append('<a class="pagenav" href="?page=1">1</a>'),e>4&&$("#phan-trang").append("..."),e>2&&$("#phan-trang").append('<a class="pagenav" href="?page='+c+'">'+c+"</a>"),e>1&&$("#phan-trang").append('<a class="pagenav" href="?page='+l+'">'+l+"</a>"),$("#phan-trang").append('<span class="current"><b>'+e+"</b></span>"),e<m-1&&$("#phan-trang").append('<a class="pagenav" href="?page='+p+'">'+p+"</a>"),e<m-2&&$("#phan-trang").append('<a class="pagenav" href="?page='+i+'">'+i+"</a>"),e<m-3&&$("#phan-trang").append("..."),e<m&&$("#phan-trang").append('<a class="pagenav" href="?page='+m+'">'+m+"</a>"),e<m&&$("#phan-trang").append('<a class="pagenav" href="?page='+p+'">»</a>'),a=t;a<=o;a++){if(s>=commentList.length){console.log("Load xong, id cuoi "+s);break}if(s++,visibleComments.includes(JSON.stringify(commentList[a])))return;var r=validator.escape(commentList[a].name),g=listArray.find(n=>n.nick===r),h=$(`
<div class="list1 comment-item"><table cellpadding="0" cellspacing="1"><tbody><tr><td width="auto"><img class="imgAvtUser" src="${g.value.avatar_link}" width="60" height="60"></td><td><a href="/user/${r}">
 <a href="/user/${r}"><b><font color="DarkSlateGrey">${g.value.name}</font></b></a><br><small><font color="#999"><i class="fa fa-clock-o"></i> ${formatDate(commentList[a].timestamp)}</font></small></td></tr></tbody></table><div class="chatbox"> <span class="textchat"> </span>${marked(validator.escape(commentList[a].comment))}</div>
</div>


 		`).hide();$("#commentSection").prepend(h),h.fadeIn(),visibleComments.push(JSON.stringify(commentList[a])),$(".comment-item").linkify(),$("#no-comments").hide()}}else 0==visibleComments.length&&$("#no-comments").show()}function loadAllComments(){var n=encodeURIComponent(`SELECT A, C, D, E WHERE B = '${thisPageUrl}'`);fetch(`{{ commentRead }}/gviz/tq?tqx=out:csv&sheet=comments&tq=${n}&headers=0`).then(n=>n.text()).then(n=>displayComments(n))}function loadNewComments(){var n=encodeURIComponent(`SELECT A, C, D, E WHERE B = '${thisPageUrl}'`);fetch(`{{ commentRead }}/gviz/tq?tqx=out:csv&sheet=comments&tq=${n}&headers=0`).then(n=>n.text()).then(n=>displayNewComments(n))}loadAllComments(),setInterval(loadNewComments,6e3);const encodeFormData=n=>Object.keys(n).map(e=>encodeURIComponent(e)+"="+encodeURIComponent(n[e])).join("&");function postComment(){var n=$("#comment-name").val(),e=$("#comment-comment").val();return fetch("{{ commentPost }}/formResponse",{method:"POST",mode:"no-cors",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:encodeFormData({"{{ commentPostUrl }}":thisPageUrl,"{{ commentPostUsername }}":n,"{{ commentPostComment }}":e})}).then(n=>{$("#comment-comment").val(""),loadNewComments()}).catch(n=>{console.log(n)}),!1}
</script>

<div class="menu">
<div class="redactor_box" style="border-bottom: 1px solid #D7EDFC;margin-bottom:2px;"><style>.color a {float:left; display: block; width: 10px; height: 10px; margin: 1px; border: 1px solid black;}</div></style>
<ul class="redactor_toolbar">
 <li class="redactor_btn_group">
 <a href="javascript:tag('*', '*')"><i class="fa fa-bold" aria-hidden="true"></i></a>
 <a href="javascript:tag('**', '**')"><i class="fa fa-italic" aria-hidden="true"></i></a>
 <a href="javascript:tag('~~', '~~')"><i class="fa fa-strikethrough" aria-hidden="true"></i></a>
 <a href="javascript:tag('[', '](https://)')"><i class="fa fa-link" aria-hidden="true"></i></a>
 <a href="javascript:tag('![](', ')', '')"><i class="fa fa-picture-o" aria-hidden="true"></i></a>
 <a href="javascript:tag('{video:', '}', '')"><i class="fa fa-video-camera" aria-hidden="true"></i></a>
 <a href="javascript:tag('{youtube:', '}', '')"><i class="fa fa-youtube-play" aria-hidden="true"></i></a>
 </li>
 <li class="redactor_btn_group">
 <a href="javascript:show_hide('sm');"><i class="fa fa-smile-o" aria-hidden="true"></i></a>
 </li>
</ul>
<div id="sm" style="display:none">
 {% for i in 1..45 %}
 <a href="javascript:tag('![](https://moleys.github.io/assets/images/aru{{i}}.png)', ''); show_hide('sm');"><img src="https://moleys.github.io/assets/images/aru{{i}}.png" width="50px" /></a>
 {% endfor %}
</div>
 <form onsubmit="return postComment()" id="form" autocomplete="off">
 <input id="comment-name" name="username" type="hidden" placeholder="" required="" value="{{func.rwurl(login)}}">
 <label><b>Nội dung: </b>(có thể sử dụng markdown)</label><br />
 <textarea id="comment-comment" name="msg" rows="4" placeholder="" required=""></textarea><br />
 <input style="display:none" type="file" id="f" accept="image/*">
 <button id="comment-submit" name="submit" type="submit" id="submit"> Chat</button> 
 <a id="upload">[ <i class="fa fa-upload" aria-hidden="true"></i> ]</a>
</div>
</div>
<div id="commentSection">
 <div id="no-comments" class="menu">
 Loading...
 </div>
</div>
<center>
 <div class="topmenu">
 <div class="pagination" id="phan-trang">
 </div>
 </div>
</center>
<script src="/js/vchat.js"></script>
{% endmacro %}


II) Thư mục js
1. Tạo tệp marked-Ext.js
function mediaParseIdFromUrl(e,i){if("youtube"===e){var o=i.match(/^.*((youtu.be/)|(v/)|(/u/w/)|(embed/)|(watch?))??v?=?([^#&?]*).*/);return o&&11==o[7].length?o[7]:void 0}if("vimeo"===e){var v=i.match(/^.*vimeo.com/(d+)/);return v&&8==v[1].length?v[1]:void 0}if("viddler"===e){var d=i.match(/^.*((viddler.com/)|(v/)|(/u/w/)|(embed/)|(watch?))??v?=?([^#&?]*).*/);return d&&8==d[7].length?d[7]:void 0}if("dailymotion"===e){var t=i.match(/^.+dailymotion.com/((video|hub)/([^_]+))?[^#]*(#video=([^_&]+))?/);return t&&(t[5]||t[3])?t[5]?t[5]:t[3]?t[3]:void 0:void 0}}
const youtubeExt = {
 name: 'youtube',
 level: 'block',
 start (src) { return src.match(/{/)?.index },
 tokenizer (src, tokens) {
 const rule = /^{youtube:([^
]+)}$/;
 const match = rule.exec(src);
 if (match) {
 return {
 type: 'youtube',
 raw: match[0],
 src: mediaParseIdFromUrl('youtube', match[1].trim())
 }
 }
 },
 renderer (token) {
 return `
<div class="video-wrapper"><iframe width="727" height="409" src="https://www.youtube.com/embed/${token.src}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
`;
 }
}

const videoExt = {
 name: 'video',
 level: 'block',
 start (src) { return src.match(/{/)?.index },
 tokenizer (src, tokens) {
 const rule = /^{video:([^
]+)}$/;
 const match = rule.exec(src);
 if (match) {
 return {
 type: 'video',
 raw: match[0],
 src: match[1].trim()
 }
 }
 },
 renderer (token) {
 return `
<video class="kvideo" width="400" controls><source src="${token.src}" type="video/mp4"></video>
`;
 }
}
marked.use({ extensions: [youtubeExt] });
marked.use({ extensions: [videoExt] });

2. Tạo tệp vchat.js
function imgur(e,a){document.querySelector(e).onchange=function(){var e=this.files[0];if(e&&e.type.match(/image.*/)){var t=new FormData;t.append("image",e);var n=new XMLHttpRequest;n.open("POST","https://api.imgur.com/3/image.json"),n.upload.onprogress=function(e){if(e.lengthComputable){var t=Math.floor(e.loaded/e.total*100)+"%";a.loading(t)}},n.onload=function(){var e=JSON.parse(n.responseText);if(200===e.status&&!0===e.success){var t=e.data;a.loaded(t.link,t.type,t.size,t.datetime)}else window.alert("Lỗi: tải lên thất bại")},n.setRequestHeader("Authorization","Client-ID 71ae7b89253621e"),n.send(t)}else window.alert("Chỉ cho phép chọn ảnh")}}document.querySelector("#upload").onclick=function(){document.querySelector("#f").click()},imgur("#f",{loading:function(e){document.querySelector("#upload").innerHTML='[ <i class="fa fa-upload" aria-hidden="true"></i> '+e+" ]"},loaded:function(e,a,t,n){var o=$("textarea").val();$("textarea").val(o+" ![]("+e+")"),document.querySelector("#upload").innerHTML='[ <i class="fa fa-upload" aria-hidden="true"></i> ]'}});
function tag(e,t){if(document.selection)document.form.msg.focus(),document.form.document.selection.createRange().text=e+document.form.document.selection.createRange().text+t;else if(null!=document.forms.form.elements.msg.selectionStart){var n=document.forms.form.elements.msg,o=n.value,s=n.selectionStart,l=n.selectionEnd-n.selectionStart;n.value=o.substr(0,s)+e+o.substr(s,l)+t+o.substr(s+l)}else document.form.msg.value+=e+t}function show_hide(e){obj=document.getElementById(e),"none"==obj.style.display?obj.style.display="block":obj.style.display="none"}
function TimeNow(){var e=new Date,t=e.getDate()+"-"+(e.getMonth()+1)+"-"+e.getFullYear()+" "+(e.getHours()+":"+e.getMinutes()+":"+e.getSeconds());document.getElementById("TimeNow").innerHTML=t}
setInterval(TimeNow, 1000);


III) Cách sử dụng

{% from '_cmS.twig' import commentSection %}

{{commentSection(current_url)}}
{{commentSection('forum')}}
{{commentSection('chat')}}
...