Пишем клиент для Голос в связке с CMS Joomla. Часть 3
Привет! На связи @captain и сегодня у нас по плану третий пост про написание web-клиента GOLOS. И он будет посвящен отображению контента поста и комментариев. Также мы покажем кто проголосовал за пост и с какой силой, когда и кем он был написан, какие его ожидают выплаты и как скоро.
Вот так это будет выглядеть:
Основной метод для получения данных поста это API вызов:
golos.api.getContent
с параметрами author
и permlink
. Но, как обычно все не так просто и нам потребуются дополнительные инструменты.
Начнем с того, что сам по себе пост может быть, как минимум, в 2 форматах. Это markdown и html. И если html наш браузер отображать умеет, то для markdown нужна будет дополнительная библиотека. Это будет marked.js, которая довольно сносно умеет отображать таблицы и блоки кода. Мы получаем данные поста в параметр data и обрабатываем их:
var result = data;
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false
});
article.text = result.body;
а после помещаем в одно из полей объекта article, где уже есть ссылка на автора и permlink. Теперь получаем дату поста:
var date = new Date(result.created);
var offset = date.getTimezoneOffset();
date.setMinutes(date.getMinutes() - offset);
var dt = date.toLocaleDateString("ru-RU") + ' ' + date.toLocaleTimeString("ru-RU");
В отличие от ленты, здесь мы указываем дату полностью, это может быть важно в некоторых случаях. Поэтому даем пользователю все инструменты для работы с постом.
Еще хотелось бы показать сколько заработал пост и через какое время ожидается выплата в первом окне. За это отвечают следующие поля:
cashout_time - время выплаты денег за текущее окно
mode - какое окно активно - первое или второе
pending_payout_value - сколько будет выплачено в первом окне
total_pending_payout_value - сколько будет выплачено во втором окне
Теперь мы можем сформировать шапку поста:
var header = document.createElement("div");
header.innerHTML = "<h1><a href='/@"+author+"/"+permlink+"' target='_blank'>"+result.title+
"</a> <br><small>"+dt+" Автор - <a href='/@"+result.author+"' title='Все посты пользователя'>@"+result.author+"</a> "+
follow + "</small></h1>" + '<p class="help-text">Голосов <strong>'+result.active_votes.length+
'</strong> на сумму <strong>'+vl+'</strong> выплата '+getCommentDate(result.cashout_time)+'</p>';
Дальше нам нужно показать аватарку пользователя. Она должна быть большая и красивая, чтобы мы видели кого мы читаем. Аватарка содержится в метаданных аккаунта и мы можем получить ее методом golos.api.getAccounts
. Так же как и картинку в превью поста, мы выводим аватар в бэкграунд элемента div с закругленными краями. А если метаданные не заполнены или информации об аватарке нет, то выводим картинку с ниндзя, так как человек явно прячется от нас:
var ava = document.createElement("div");
ava.style.float = 'left';
ava.id = 'ava';
document.getElementById('query_header').appendChild(ava);
golos.api.getAccounts([author], function(err, response){
if(response)
{
var ava = document.getElementById("ava");
if(response[0].json_metadata != 'undefined' && response[0].json_metadata != '{}' && response[0].json_metadata != '')
{
var metadata = JSON.parse(response[0].json_metadata);
if(metadata.profile != 'undefined')
{
if(metadata.profile.profile_image != 'undefined')
{
ava.style.backgroundImage = "url('"+metadata.profile.profile_image+"')";
}else{
ava.style.backgroundImage = "url('/ninja.png')";
}
}else{
var ava = document.getElementById("ava");
ava.style.backgroundImage = "url('/ninja.png')";
}
}else{
var ava = document.getElementById("ava");
ava.style.backgroundImage = "url('/ninja.png')";
}
ava.classList.add('ava_div');
}
});
После этого выводим текст поста. Пропустим его через markdown фильтр и добавим на страницу. Тут все просто:
main_div.innerHTML = marked(article.text);
Еще нам хотелось бы видеть как кто проголосовал за пост. Но тут возникает такой момент, что голосов может быть много, нужно их как-то компактно показать. Поэтому мы спрячем их под спойлер:
golos.api.getActiveVotes(author, permlink, function(err, data){
if(data)
if(data.length > 0)
{
var s = '';
data.forEach(function(operation){
s = s + "<a href='/@"+operation.voter+"' title='"+operation.percent / 100 +"%'>@"+operation.voter+"</a> ";
});
document.getElementById('voters').innerHTML = '<hr><div>Оценили ('+data.length+'): <span class="tt" onclick="spoiler(\'all_votes\'); return false">показать</span> <span id="all_votes" class="terms" style="display: none;"><small>' + s + '</small></span></div>';
}
});
Таким образом мы видим сколько людей проголосовало за пост. А раскрыв спойлер, мы сможем увидеть кто и с какой силой это сделал поименно.
Вот практически и все. Остается только показать комментарии. В блокчейне голос цепочка комментариев записывается со ссылкой на родителя, которая хранится в parent-permlink
. И у нас есть задача построить из набора таких цепочек дерево комментариев. Для этого мы воспользуемся замечательным приемом - рекурсией. Вот так мы вытащим комментарии первого уровня:
golos.api.getContentReplies(author, permlink, function(err, data){
if(data.length > 0)
{
data.forEach(function(operation){
var main_div = addComentX(operation);
document.getElementById('answers_list').appendChild(main_div);
getRepliesX(operation.author, operation.permlink, main_div)
});
}
});
а вот так все остальные:
function getRepliesX(author, permlink, parent)
{
golos.api.getContentReplies(author, permlink, function(err, data){
if(data.length > 0)
{
data.forEach(function(operation){
var div = addComentX(operation);
div.classList.add("depth2");
parent.appendChild(div);
getRepliesX(operation.author, operation.permlink, div);
});
}
});
}
Вывод самого комментария реализует функция:
function addComentX(operation)
{
// вот этот блок нужен чтобы все красиво вывести со смещением
var main_div = document.createElement("div");
main_div.classList.add("panel");
main_div.classList.add("panel-default");
var header = document.createElement("div");
header.classList.add("panel-heading");
var actions = document.createElement("div");
actions.style.textAlign = 'right';
actions.style.marginBottom = '5px';
//а тут все данные о комментарии - дата, автор, оплата
var dt = getCommentDate(operation.created);
var vl = operation.total_pending_payout_value;
if(operation.total_payout_value > operation.total_pending_payout_value)
{
vl = operation.total_payout_value;
}
var ava = document.createElement("div");
ava.style.float = 'left';
header.innerHTML = "<div><h3>"+operation.title+" <small>"+dt+" - <a href='/@"+operation.author+"' title='Все посты пользователя'>@"+operation.author+"</a></small></h3>" + '<p class="help-text"> Голосов '+operation.active_votes.length+' на сумму <strong>'+vl+'</strong></p></div>';
main_div.appendChild(header);
header.appendChild(ava);
var answer = document.createElement("div");
answer.classList.add("panel-body");
answer.innerHTML = marked(operation.body);
main_div.appendChild(answer);
main_div.appendChild(actions);
document.getElementById('answer').style = 'display: block';
golos.api.getAccounts([operation.author], function(err, response){
if(response)
{
if(response[0].json_metadata != 'undefined' && response[0].json_metadata != '{}' && response[0].json_metadata != '')
{
var metadata = JSON.parse(response[0].json_metadata);
if(metadata.profile != 'undefined')
{
if(metadata.profile.profile_image != 'undefined')
{
//var ava = document.getElementById("ava");
ava.style.backgroundImage = "url('"+metadata.profile.profile_image+"')";
ava.classList.add('ava_div');
}else{
ava.style.backgroundImage = "url('/ninja.png')";
ava.classList.add('ava_div');
}
}else{
ava.style.backgroundImage = "url('/ninja.png')";
ava.classList.add('ava_div');
}
}else{
ava.style.backgroundImage = "url('/ninja.png')";
ava.classList.add('ava_div');
}
}
});
return main_div;
}
В следующем посте нас ждет добавление постов и комментариев, голосование за посты, комментарии и установка флагов.
И немного пиара. @captain это делегат голоса. Вот его делегатский пост https://golos.io/@captain/post-delegata-captain/
@captain много чего делает для голоса и много чего еще сделает. Поэтому не поленитесь и проголосуйте за него тут https://golos.io/~witnesses или тут https://goldvoice.club/witnesses/