Блокнот + JavaScript + голос = Трансляция Апвотинга, Фолловинга, новых пользователей, голосов за делегатов и прайсфида.
Продолжение урока
Предыдущий урок здесь: Доступный JavaScript на прикладном примере создания страницы/сайта с действиями пользователей голоса в реальном времени
В прошлых уроках мы начали разбирать состав javascript с созданной в блокноте странички, которая транслирует статистику голоса в реальном времени, мы научились посылать запросы голосу и получать на них ответы.
Тестовый пример https://vikx.tumblr.com/
В этом посте мы научимся фильтровать и выводить получаемые данные от голоса:
- Голоса за пользователей и сила отданного голоса
- Комментарии к постам
- Создание постов
- Фолловинг
- Прайс фиды от делегатов со стоимостью пары (Золотой/Голос)
- Голосования за делегатов
- Новые пользователи на голосе
Такая фильтрация удобна тем, что каждый ответ от голоса мы сможем на своей странице оформить по - своему.
Например на тестовой странице https://vikx.tumblr.com/ у нас лента вида:
Вася
комментируетпетю
-Привет вася!
Оля
голосует заКолю
с силой10000
Лариса
подписывается наАльберта
Но по сути мы получаем только массив разделенных данных, что дает нам возможность оформить выдачу данных как угодно. Мы просто сможем подставлять имена в наши заготовки применяя разные практики визуализации.
Ответы запутанные для человеческого глаза, но удобные для обработки нашим приложением.
Мы научимся их обрабатывать и вставлять в нашу страницу приложения.
Прежде мы научились запрашивать данные из блоков get_block
. Такой запрос возвращает нам общий массив данных из блока, которые мы отфильтруем до транзакции > операции:
blockdata = JSON.stringify(data.result.transactions[0].operations[0]);
И в переменной blockdata
у нас будет один из множества вариантов содержания операции. Сперва рассмотрим голосования (апвотинг)
Кто за кого голосует в реальном времени
Если в блоке было зафиксировано голосование, то отобразится оно следующим образом:
["vote", {
"voter": "dmilash",
"author": "elixir-golos",
"permlink": "reliz-exgolos-v0-2-open-sors-jsonrpc-klient-dlya-golosa-na-elixir-erlang",
"weight": 5000
}]
- voter - тот кто проголосовал
- author - тот за кого голосовали
- permlink - ссылка на пост
- weight - вес голоса
Мы уже знаем как разбирать такие массивы и записывать отдельные данные в отдельные переменные. Создадим переменные.
Например что бы получить значение voter, нам нужно в переменную записать путь до значения voter.
data.result.transactions[0].operations[0][1].voter;
для автора
data.result.transactions[0].operations[0][1].author;
И так далее. Облегчим и сократим код: поскольку у нас строки отличаются только окончанием, мы сделаем сокращение для одинаковых частей строки. Сокращенная версия будет в переменной tx.
tx = data.result.transactions[0].operations[0][1];
И теперь мы можем выбирать объекты сокращенными строками
tx = data.result.transactions[0].operations[0][1];
$voter = tx.voter; //
$power = tx.weight;
$author = tx.author;
$permlink = tx.permlink;
Теперь в этих четырех переменных имя голосующего, вес голоса, имя автора получившего голос и ссылка на пост. Мы можем подготовить наш html и вставлять имена и значения в заготовленные места.
Но есть проблема в фильтрации данных, что бы стало понятней, перейдем к следующему виду операции - комментариям
Разделяем голоса от комментариев и других данных
Комментарии в нашем потоке выглядят так. К слову с префиксом comment в блоках еще и создаваемые посты, что не очень удобно.
["comment", {
"parent_author": "whiskardi",
"parent_permlink": "re-anela-re-toplight-re-konstantin-
nuzhno-li-v-golose-razzhiganie-nenavisti-
oskorbleniya-i-neuvazhenie-pravil-soobshestva-20170203t150954836z",
"author": "smolalit",
"permlink": "re-whiskardi-re-anela-re-toplight-re-konstantin-nuzhno-li-v-golose-razzhiganie-nenavisti-oskorbleniya-i-neuvazhenie-pravil-soobshestva-20170203t165212985z",
"title": "",
"body": "Ну не всех :))) Но и им (быдлам) там местечко найдется.",
"json_metadata": "{\"tags\":[\"ru--golos\"]}"
}]
Теперь о проблеме.
Заметили, что в комментариях тоже есть переменная author как и в голосовании? То есть во время приемов блоков, нашему скрипту надо как-то явно указывать, где author в рамках комментария, а где в рамках голосования и т.д. Если мы хотим выводить оформленные данные для каждой операции, нам нужно как-то разделить эти операции по типу данных.
Мы видим, что апвот от коммента отличается первым значением:
["vote", {
// данные
}]
["comment", {
// данные
}]
vote и comment. Сделаем переменную, которая будет сохранять категорию данных
trigger = data.result.transactions[0].operations[0][0];
Переменная триггер теперь содержит значение вида vote, comment или другое, которое мы будем получать.
Приступим к выводу стрима на нашу страничку!
Для этого мы заранее должны были создать элемент на странице, куда будем вставлять данные.
Мы создали такой:
<div id="filterdata"> </div>
По вкусу оформили его в css, например я сделал одну колонку с фильтрованными данными, а вторую с нефильтрованными, что бы ничего не пропускать и видеть несоответствия в логике выдачи данных. А логику я придумал такую:
Внутри условия, которое вы должны помнить по прошлому посту
if (data.id === 3 && merkle !== "0000000000000000000000000000000000000000"){
"Если это ответ на запрос с id 3 (который запрашивает данные блока) и блок не пустой, то делать:"
Перечисляем наши переменные со значениями
tx = data.result.transactions[0].operations[0][1];
trigger = data.result.transactions[0].operations[0][0];
$voter = tx.voter;
$power = tx.weight;
$author = tx.author;
$permlink = tx.permlink;
// Это далеко не все, которые нужно создать!
// Просто пока работаем с выводом только голосований
И теперь делаем условие по типу данных:
if (trigger == 'vote'){
// Что-то сделаем тут
}
Условие звучит как "Если триггер vote (голосование), то выполнять действие.
Нашим действием будет - вставка значений голосования в страницу, в div элемент #filterdata.
Для этого воспользуемся JS функцией вставки html в начало элементов:
document.getElementById('filterdata').insertAdjacentHTML('afterbegin',votehtml);
Итого, в случае, если в полученном блоке у нас есть операция голосования, срабатывает триггер vote и мы вставляем в страницу данные, наши данные это 4 переменные , которые мы должны вместе с html поместить в переменную votehtml и вставить в div#filterdata
Состав переменных для голосования:
- $voter =Голосующий;
- $power = Сила;
- $author = Автор;
- $permlink = Ссылка;
Расположим их для вставки, смешав с html текстом, что бы это имело какой-то вид
votehtml = '<div>'+$voter+' голосует за '+$author+'. Сила '+$power+' </div>'
Теперь в наш поток данных понятен глазу. Снизу неоформленное голосование, сверху оформленное.
Я не стал добавлять ссылку на пост, хотя в переменную votehtml
вы можете вставить переменные с именами, ссылками и силой как угодно, можно стилизовать имена цветами, добавить иконку апвотинга, что бы было понятно, что это голосование, так же можно и присвоить аватарки пользователям (это будет в следующих постах).
Собственно основной путь пройден, самое важно на голосе - голоса, и теперь мы можем вывести поток голосов где захотим. Можно на своем сайте, можно смотреть страницу с пк, можно вставлять ее в виде iframe себе или другим продвигая голос :)
Комментарии.
Сложнее из-за смеси данных.
Приступим к разбору комментариев. Так же как и для голосований, мы сделаем условие-фильтр с триггером comment
:
if (trigger == 'comment'){
// создадим и вставим элемент с комментарием
}
Проблема будет в том, что в базе голоса объект comment смешан с постами. То есть и новые посты, и новые комменты к постам, будут в данном массиве.
Вот к примеру массив данных комментария:
["comment", {
"parent_author": "grumlin",
"parent_permlink": "vazhnoe-pravilo-estafety-10-faktov-o-sebe",
"author": "galager",
"permlink": "re-grumlin-vazhnoe-pravilo-estafety-10-faktov-o-sebe-20170203t192929846z",
"title": "",
"body": "а если я отредактировала и
поставила этот тег первым,
а в итоге он все равно второй, что делать?
доктор, это лечится? я умру?",
"json_metadata": "{\"tags\":[\"ru--novostx\"]}"
}]
А вот массив данных обычного поста
["comment", {
"parent_author": "",
"parent_permlink": "ru--kodirovka",
"author": "redhat",
"permlink": "kak-kodiruyut-ot-alkogolizma",
"title": "Как кодируют от алкоголизма?",
"body": "Текст поста.......................... ","
json_metadata ":" {\
"tags\":[\"ru--kodirovka\"]}"
}]
Если мы сделаем вывод комментариев как-то так
author+ комментирует parent_author+:
title + body
То в итоге у нас в первом случае (в случае комментария) будет так:
grumlin комментирует galager:
" "
"а если я отредактировала и
поставила этот тег первым..."
" " пустые кавычки, так как в комментарии title не заполнен.
Во втором случае (в случае с постом) у нас будет:
redhat комментирует " "
Как кодируют от алкоголизма?
Текст поста..........
Опять пустые кавычки, так как в случае с созданием поста не указан parent_author.
Таким образом, нам нужно поделить комментарии на два вида: собственно комментарии и новые посты. Отличить их можно отсутствием parent_author. Технически не отсутствием, а пустым значением " ".
Для этого сделаем еще одно условие внутри условия "если (триггер = коммент)".
Но сначала сделаем переменные с недостающими данными.
$parent = tx.parent_author; // Родитель-автор. Тот кого комментят. Есть только в комментах
$body = tx.body; // Тело коммента или поста
$title = tx.title; // Заголовок. Есть только в постах
Добавим их к списку наших переменных, помним - переменная для author у нас уже есть.
Условие разделения постов от комментариев с последующим размещением на странице.
/// Если триггер равен комменту
if (trigger == 'comment'){
// Если в блоке с данными автор родитель не является пустым значением
if ($parent !== ""){
// Выводим сообщение заточенное под комментарий
commthtml = '<div id="item" class="myJson">'+$author+' комментирует '+$parent+': '+$body+' </div>'
document.getElementById('filterdata').insertAdjacentHTML('afterbegin',commthtml);
//В ином случае, если автор родитель пустое значение, то это пост и выводим другой html
} else {
// html заточенный под пост.
posthtml = '<div id="item" class="myJson">'+$author+' разместил пост <h4>'+$title+'</h4>'+$body+'</div>'
document.getElementById('filterdata').insertAdjacentHTML('afterbegin',posthtml);
}
}
У нас получилось!
Теперь в нашей ленте видно голосования, комментарии (вместе с их содержимым) и новые посты.
[
На данном этапе наш JavaScript таков:
Подключение и отправка запроса на динамические данные с интервалом 3000ms
[
Хуки для точного роста блоков 1 в 3 сек. И отправка запросов на данные аккаунта и содержание блоков
[
Обработка полученных данных от блока и вывод голосований, комментариев и постов в ленту на странице
[
Фрагмент кода на последнем скрине будет нашим основным полем деятельности и мы продолжим делать вывод остальных данных
Что еще хотим вывести
- Подписки
- Упоминания и транзакции
- Регистрация новых пользователей
- Обновление аккаунтов
- Текущую силу голоса
- Форму для указания стартового блока
- Форму для поиска данных по желаемому аккаунту
- Торги на внутренней бирже (?)
- Ввод/Вывод токенов пользователями (?)
Выводим подписки (фолловинг)
В отличие от комментариев и голосования, подписки не имеют толковой подписи, очевидно этот функционал добавляли позднее и опционально. Вот пример операции, которая содержит данные о подписке:
["custom_json", {
"required_auths": [],
"required_posting_auths": ["on0tole"],
"id": "follow",
"json": "[\"follow\",{\"follower\":\"on0tole\",\"following\":\"piranya\",\"what\":[\"blog\"]}]"
}]
Когда мы будем получать в ответе такую операцию, в триггер будет записываться custom_json
- сделаем условие:
// Если триггер custom_json (обычно это фолловинг)
if (trigger == 'custom_json'){
// тут будем выполнять остальные действия связанные с подпиской
}
Теперь нам нужно указать в переменных путь до конкретных объектов с данными. Тут немного сложней чем было раньше, так как информация о фолловинге вложена матрешкой в custom_json > json
custom_json", {
....
"json": "[\"follow\",{\"follower\":\"on0tole\",\"following\":\"piranya\",\"what\":[\"blog\"]}]"
}
Нам нужно добраться до follower и following и записать их в переменные
Вот как мы поступим:
var follow = JSON.parse(tx.json)[1],
$follower = follow.follower,
$followin = follow.following;
В первую переменную мы добавили путь к свойству json при этом применили JSON.parse
для перевода строки json в объекты
Во вторую и третью мы добавили имя фолловера и фолло.. фолловнящегося :)
По уже известному принципу мы сможем вывести переменные в желаемом для нас html формате
Фрагмент кода который отвечает за вывод фолловинга:
Не исключено, что custom_json
будет в будущем нести и другие данные.
Трансферы, упоминания
Еще один вид операции который мы можем увидеть в потоке - transfer
Это может быть передача личных средств
["transfer",{"from":"polyideic","to":"mapala.ico","amount":"80.000 GBG","memo":"polyideic"}]
Работа mention bot тоже из категории трансферы
["transfer",{"from":"mentionbot","to":"vik",
"amount":"0.001 GOLOS",
"memo":"Вас упомянул пользователь...."
}]
Ну и все остальное, что вы можете найти у себя в кошельке на вкладке /transfers
Для нас это уже должно быть легко, создаем переменные и оформляем html
На выходе получаем:
или так
Прайс фиды от делегатов
Возможно нам так же будет интересно вывести котировки от делегатов.
["feed_publish", {
"publisher": "jesta",
"exchange_rate": {
"base": "1.780 GBG",
"quote": "1.000 GOLOS"
}
}]
Привычным алгоритмом: если триггер feed_publish
, затем переменные, затем вставляем на страницу.
Теперь и актуальные прайсфиды валют голоса в нашем потоке!
Новые пользователи
Данные о создании аккаунта:
["account_create", {
"fee": "5.000 GOLOS",
"creator": "golosio",
"new_account_name": "irinativa",
"owner": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
["GLS6R8eeA9rk3ec5WK43bYWrGbWK2XQYWPGjgThwDi4eeZuoPDC3g", 1]
]
},
"active": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
["GLS7pX2CGTcS7XjtiLJTTo6GLU4f5FNNh7sM3HpUxkvdtFE9ki87W", 1]
]
},
"posting": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
["GLS85fULzSASb3XgW85kwMMmed5vCLS5PXCi3v7Ab8x4Ljo1ZyTNm", 1]
]
},
"memo_key": "GLS6Cbq4u1gHo8ZGUjj1YXGHrBNnmRtwS5oXvWvGPFP2qvR8FKXLc",
"json_metadata": "{}"
}]
Нам интересно только new_account_name
. Но так как в последнее время много новых аккаунтов с БМ, мы будем брать в переменную еще и creator
. Так как у БМ он другой.
Кроме того мы можем видеть и обновление аккаунтов триггером account_update
- но я не заметил интересных данным там, так как пока обновлять в аккаунте пользователям особо нечего
Голоса за делегатов
["account_witness_vote", {
"account": "good-karma",
"witness": "phenom",
"approve": true
}]
Пишем привычное условие
И на 4-й строчке:
Заключение
Итак, мы научились выводить самые интересные действия пользователей используя при этом обычную html страничку. Добавив интересную анимацию и оригинальный дизайн страницы - вы сможете повесить ее на любой беплатный хостинг или блоговый движок, который позволяет редактировать шаблоны.
А используя Service Worker или PWA вы сможете из страницы сделать кросс платформенное приложение.
Разумеется, базовый функционал желательно расширить. Фильтры по юзернеймам, датам и событиям, возможность голосования и многое другое, что нам предложит api голоса.
А как насчет iframe баннера на вашем сайте для привлечения пользователей? :)
Реклама голоса, в которой будет фид активности, красноречиво говорящей о том, что голос платформа, где за пользу вам платят:
Продолжение следует!
Ссылки:
- Весь код страницы: http://pastebin.com/euAuA9KM
- Рабочая страница: https://vikx.tumblr.com/ (в коде из pastebin все аккуратней, стр просто для примера)
- Прошлые посты: https://golos.io/@vik