Files
remark42/web/app/render.js
T
2018-01-23 20:15:35 +02:00

144 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import tmpl from 'blueimp-tmpl';
import { nodeId } from './settings';
import fetcher from './fetcher';
let node = null;
let afterInit = null;
if (document.readyState !== 'complete') {
window.addEventListener('DOMContentLoaded', initNode);
} else {
initNode();
}
function initNode () {
if (node) return;
node = document.getElementById(nodeId);
if (!node) return;
if (afterInit) {
afterInit();
}
}
function handleClick(rootNode, e) {
if (!e.target) return;
if (e.target && e.target.classList.contains('remark42__vote')) {
handleVote(rootNode, e);
}
}
function handleVote(rootNode, e) {
const { target: node } = e;
if (node.classList.contains('remark42__vote_selected')) return;
const commentId = node.closest('.remark42__comment').dataset.id;
if (node.classList.contains('remark42__vote_type_up')) {
console.log('+1');
changeScore(rootNode, 1);
fetcher.put(`/vote/${commentId}?url=https://radio-t.com/p/2017/12/16/podcast-576/&vote=1`);
} else {
console.log('-1');
changeScore(rootNode, -1);
fetcher.put(`/vote/${commentId}?url=https://radio-t.com/p/2017/12/16/podcast-576/&vote=-1`);
}
node.classList.add('remark42__vote_selected');
}
function changeScore(rootNode, delta) {
const valueNode = rootNode.querySelector('.remark42__score-value');
const currentValue = parseInt(valueNode.dataset.value);
const newValue = currentValue + delta;
valueNode.dataset.value = newValue;
valueNode.textContent = Math.abs(newValue);
}
export default data => {
// TODO: link to profile?
// TODO: link to comment?
// TODO: add photo?
const templateComment = `
<div
class="remark42__comment remark42__comment_level_{%= o.mods.level %} {%= o.mods.view ? ('remark42__comment_view_' + o.mods.view) : '' %}"
data-id="{%= o.id %}">
<img src="{%= o.user.picture %}" alt="" class="remark42__avatar">
<div class="remark42__content">
<div class="remark42__info">
<a href="#" class="remark42__username">{%= o.user.name %}</a>
<span class="remark42__score">
<a href="#" class="remark42__vote remark42__vote_type_up">vote up</a>
<span class="remark42__score-sign">{%= o.score.sign %}</span>
<span class="remark42__score-value" data-value="{%= o.score.rawValue %}">{%= o.score.value %}</span>
<a href="#" class="remark42__vote remark42__vote_type_down">vote down</a>
</span>
<span class="remark42__time">{%= o.time %}</span>
</div>
<div class="remark42__text">
{%# o.text %}
</div>
</div>
</div>
`;
const renderComment = ({ comment, level }) => {
const time = new Date(comment.time);
// TODO: which format for datetime should we choose?
// TODO: add smth that will count 'hours ago'
// TODO: check out stash's impl
const timeStr = `${time.toLocaleDateString()} ${time.toLocaleTimeString()}`;
const data = {
...comment,
time: timeStr,
score: {
rawValue: comment.score,
value: Math.abs(comment.score),
sign: comment.score > 0 ? '+' : (comment.score < 0 ? '' : ''),
},
mods: {
level: level > 5 ? 5 : level,
view: comment.user.admin ? 'admin' : '', // TODO: add default view or don't?
},
};
return tmpl(templateComment, data);
}
const renderThread = ({ comment, replies, level }) => {
let result = [renderComment({ comment, level })];
if (replies) {
result = result.concat(replies.map(thread => renderThread({ ...thread, level: level + 1 })));
}
return result.join('');
};
const render = () => {
const result = data.comments.reduce((acc, thread) => acc.concat(renderThread({ ...thread, level: 0 })), []).join('');
node.className = 'remark42';
node.innerHTML = result;
node.addEventListener('click', handleClick.bind(null, node));
};
if (node) {
render();
} else {
afterInit = render;
}
}