<html>
<head>
<meta charset="utf-8">
<title>Ardor Tweet v0.0.1 using Bitswift token</title>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"></script>
<style>
*,
*:before,
*:after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial;
background-color: #e6ecf0;
}
.box {
padding: 1em;
}
input {
width: 100%;
padding: 1em;
outline: none;
border: 1px solid #f2f2f2;
}
.message-list {
margin: 0;
padding: 0;
}
.message-list li {
padding: .2em;
margin-top: 1em;
margin-bottom: 1em;
background-color: #f2f2f2;
}
.app-layout {
display: grid;
height: 100vh;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
}
.header { background-color: #fff; }
.teams { background-color: #fff; text-align: center; color: #333;}
.channels { background-color: #e6ecf0;}
//.channels { background-color: #4ab3f4; color: #eee;}
.main { background-color: #ffffff; color: #333;}
.write { background-color: #f2f2f2; }
.login { background-color: #f2f2f2; }
.teams {
font-size: 80%;
grid-column: 1;
grid-row: 1;
border-bottom: 1px solid #ccc;
}
.channels {
grid-column: 1;
grid-row: 2 / 5;
}
.header {
grid-column: 2;
grid-row: 1;
border-bottom: 1px solid #ccc;
color: #eee;
}
#channel_name {
font-weight: bold;
font-size:120%;
color:#000;
}
#channel_address {
font-size: 100%;
margin-left: 0.3em;
color: #aaa;
}
.channel_info {
font-size: 90%;
padding-left: 1em;
padding-top:0.2em;
}
.main {
grid-column: 2;
grid-row: 2;
padding: 0 1em;
overflow-y: scroll;
background-color: #e6ecf0;
}
._messages{
grid-column: 2;
grid-row: 3;
}
.input {
grid-column: 2;
grid-row: 4;
}
a.channel {
width: 100%;
font-size:120%;
color: #999;
text-decoration: none;
text-align: center;
padding: 1em 0;
margin: 0;
display:block;
}
.channles-list {
list-style-type: none;
padding:0;
}
.channles-list li {
list-style-type: none;
padding:0;
margin:0;
}
div.message{
margin: 2em;
padding: 1em;
background-color: #fff;
}
div.notify {
margin: 0.5em 2em 0em 2em;
padding:1em;
}
.notice {
border: 1px solid #006600;
background-color: #00cc00;
}
.error {
border: 1px solid #660000;
background-color: #990000;
color: #eee;
}
div.message_body {
padding-top: 0.5em;
padding-left: 0.8em ;
}
span.sender {
font-weight: bold;
}
span.datatime {
font-size: 80%;
color: #aaa;
}
.account_note {
font-weight: normal;
font-size: 90%;
color: #999;
}
a.selected_channel {
font-weight: bold;
color: #000;
border: 1px solid #aaa;
//background-color: #e60cf0;
}
#current_login_account {
margin:0.3em 0.3em;
margin-bottom: 0.5em;
color: #333;
}
#current_login_name {
font-size: 120%;
}
#select_node {
width: 90%;
}
.app_info {
font-size: 75%;
margin-left: 3em;
border: 1px solid #aaa;
padding: 0.5em;
margin-top: 1.5em;
}
.message_body span.at_reply {
color: #4ab3f4;
}
span.at_reply:hover, .repliable span.sender:hover {
cursor: pointer;
}
.notify {
display: none;
//float:left;
//width:60%;
}
div.self {
float:right;
clear:both;
}
div.direct_message {
width: 45%;
min-width: 190px;
clear: both;
}
.extra_about p {
margin: 1em 2em;
font-size:110%;
}
.extra_about li {
padding:0.3em;
}
#account_balance {
color:#aaa;
font-size:80%;
}
</style>
<style>
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
.modal-content {
position: relative;
background-color: #fefefe;
margin: auto;
padding: 0;
border: 1px solid #888;
width: 80%;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
-webkit-animation-name: animatetop;
-webkit-animation-duration: 0.4s;
animation-name: animatetop;
animation-duration: 0.4s
}
@-webkit-keyframes animatetop {
from {top:-300px; opacity:0}
to {top:0; opacity:1}
}
@keyframes animatetop {
from {top:-300px; opacity:0}
to {top:0; opacity:1}
}
.close {
color: #555;
float: right;
font-size: 28px;
font-weight: bold;
}
.notify .close {
color: #333;;
float: right;
font-size: 120%;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.modal-header {
padding: 2px 16px;
background-color: #e6ecf0;
color: #666;
}
.modal-body {padding: 1em 1em 1em 1em;}
.modal-footer {
padding: 2px 16px;
background-color: #5cb85c;
color: white;
}
.action_buttons{
float:right;
margin-right:3em;
}
.action_buttons button, .modal button, button.unfollow, .fixed_content button{
font-size:110%;
color: #fff;
background-color: #4ab3f4;
border-radius: 8px;
padding:8px 12px;
font-weight: bold;
text-decoration: none;
border: none;
}
button.unfollow{
background-color: red;
}
button#btn_tweet {
display:none;
}
.modal textarea {
width:100%;
height: 6em;
}
.unconfirmed_message{
background-color: #ffff00;
-webkit-animation-name: example; /* Safari 4.0 - 8.0 */
-webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */
animation-iteration-count: infinite;
animation-name: slow_blink;
animation-duration: 4s;
}
.new_message {
background-color: #ffcc00;
-webkit-animation-name: example; /* Safari 4.0 - 8.0 */
-webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */
animation-name: fade_in;
animation-duration: 4s;
}
@-webkit-keyframes fade_in {
from {background-color: #00ff00;}
to {background-color: white;}
}
@keyframes fade_in {
from {background-color: #00ff00;}
to {background-color: white;}
}
@keyframes slow_blink {
from {background-color: #ffff00;}
to {background-color: white;}
}
</style>
</head>
<body>
<div id="modal_login" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h3></h3>
</div>
<div class="modal-body">
<input type="password" style="text-align:left;margin-top:8px;height:1em;" id="text_passphrase" placeholder='Input Passphrase here to Login.'></input>
<p style="text-align:right;"><button id="_login" style="">Login</button></p>
</div>
</div>
</div>
<div id="modal_tweet" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h3>What's happening?</h3>
</div>
<div class="modal-body">
<textarea type='text' placeholder='Max 500 characters.' id='tweet_message' maxlength="500" ></textarea>
<p style="text-align:right;"><button id="_tweet" style="">Tweet!</button></p>
</div>
</div>
</div>
<div id="modal_reply" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h3>Reply to: <span id="reply_name"></span> <span id="reply_account"></span> </h3>
</div>
<div class="modal-body">
<textarea type='text' placeholder='Max 500 characters.' id='tweet_reply' maxlength="500" ></textarea>
<p style="text-align:right;"><button id="_reply" style="">Reply</button></p>
</div>
</div>
</div>
<div id="modal_retweet" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">×</span>
<h3>Retweet from <span id="retweet_from_name"></span> <span id="retweet_from_account"></span> </h3>
</div>
<div class="modal-body">
<textarea type='text' placeholder='Max 500 characters.' id='retweet_message' maxlength="500" ></textarea>
<p style="text-align:right;"><button id="_retweet" style="">Retweet</button></p>
</div>
</div>
</div>
<div class='app-layout'>
<div class='teams box'>
<div id='current_login_name'></div>
<!-- <span id='account_balance'></span> -->
<div id='current_login_account'></div>
<div id='current_login_desc'></div>
</div>
<div class='channels box'>
<ul class='channles-list'>
<li><a class="channel" id="channel_home" data-channel-name="home" href="#" >Home</a></li>
<li><a class="channel" id="channel_at_me" data-channel-name="at_me" href="#" >@Me</a></li>
<li><a class="channel" id="channel_tweets" data-channel-name="tweets" href="#" >My Tweets<span id="meta_tweets"></span></a></li>
<li><a class="channel" id="channel_tweets_replies" data-channel-name="tweets_replies" href="#" >Tweets & Replies</a></li>
<hr/>
<li><a class="channel" id="channel_following" data-channel-name="following" href="#" >Following<span id="meta_following"></span></a></li>
<li><a class="channel" id="channel_followers" data-channel-name="followers" href="#" >Followers<span id="meta_followers"></span></a></li>
<hr/>
<li><a class="channel" id="channel_direct_messages" data-channel-name="direct_messages" href="#" >Direct Messages</a></li>
<hr/>
<li><a class="channel" id="channel_about" data-channel-name="about" href="#" >About</a></li>
</ul>
</div>
<div class='header box'>
<div class='action_buttons'>
<button id="btn_tweet" style="">Tweet!</button>
<button id="btn_login">Login</button>
</div>
</div>
<div class='main box' style=''>
<div class="notify"><span class="close">×</span><span class="text"></span></div>
<div class="unconfirmed_messages"></div>
<div class="fixed_content extra_following" style="display:none;">
<p style="text-align:center;">
<input type="text" style="text-align:left;margin-top:8px;font-size:110%;;width:60%;margin-right:10px;" id="following_account" placeholder='Input the account address you want to following.'></input>
<button id="_following" style="">Follow</button>
</p>
<div id="following_desc"></div>
</div>
<div class="fixed_content extra_direct_messages" style="display:none;">
<p style="text-align:center;">
<select id="direct_message_recipient" style="text-align:center;margin-top:8px;font-size:150%;;width:95%;margin-right:10px;padding:0.5em 0.5em;"></select>
</p>
</div>
<div class="fixed_content extra_about" style="">
<p>For testing, input passphrase "1" or "0" to login.</p>
<h1>About</h1>
<p>This is a Twitter clone completely building on Ardor platform, or precisely, the Bitswift child-chain of Ardor.</p>
<p>I <i>(https://galeki-101.medium.com/twitter-clone-on-ardor-c30b923a6a4a)</i> must say I'm no professional developer and only planned to learn some Ardor by doing this, but turns out got most functions done.</p>
<h1>Guide</h1>
<p>This is Qora QNS web3 <a target="_top" href="/tweet6">/tweet6</a> page, via localhost Ardor full node : http://127.0.0.1:27876 ( HTML source code line 590 var _node_url = ). Ardor running locally.<br>
(Ignis child-chain version : goto Qora QNS /tweet1 to /tweet3, GPS chaild-chain version : /tweet4)
</i></p>
<p>Works under Chrome 67 and Firefox 61, not with Edge and IE.</p>
<p>You must have a Ardor account which you can login with your passphrase, and some BITS coins for tweeting or following.</p>
<p>At the rate when this app is writing(March 14,2024), sending a tweet cost 0.001 BITS and following cost 0.001 BITS. </p>
<h1>How it works</h1>
<p>This 'Ardor Tweet' only follows some simple <strong>Protocols</strong>: </p>
<ul>
<li>Every Ardor account is a <strong>Tweet account</strong>.</li>
<li>The name of Ardor account is the <strong>Username of the Tweet account</strong>.</li>
<li>Every <strong>Unencrypted</strong> message sending to account itself is a <strong>Public Tweet</strong>.</li>
<li>Every <strong>Unencrypted</strong> message sending to other account is a <strong>Public @-Reply</strong>.</li>
<li>Every <strong>Encrypted</strong> message sending to other account is a <strong>Direct Message</strong>.</li>
<li>Setting a property naming 'following' to other account means you are <strong>Following him/her</strong>.</li>
</ul>
<p>This app is just a implementation of those protocols.</p>
<p>Actually you don't have to use this, every implementation of those protocols can work perfectly with each other. And you can even do all those things within Message section of the official Ardor client.</p>
<h1>More features?</h1>
<p>This app using only basic Ardor API calls and without designing any data structure of my own, and all messages are plain text.</p>
<p>Simply sending a designed custom json object instead of plain text will open a whole new gate for new features.</p>
<p>Just leave the idea. :p</p>
</div>
<div class="messages">
</div>
<div class="_direct_messages extra_direct_messages fixed_content" style="overflow:auto;height:85%">
<div class="direct_messages"></div>
<div class="fixed_content extra_direct_messages unconfirmed_direct_messages"></div>
</div>
</div>
<div class="box input fixed_content extra_direct_messages" style="display:none;">
<textarea type='text' placeholder='Max 500 characters.' id='_direct_message' maxlength="500" style="width:100%;height:100px;"></textarea>
<p style="text-align:right;"><button id="_send_direct_message" style="" onclick="send_direct_message()">Send</button></p>
</div>
</div>
</body>
<script>
$('.notify span.close').click(function() {
$('.notify').hide();
});
$('#btn_login').click(function() {
$('#modal_login .modal-header h3').text($(this).text());
$('#modal_login #_login').text($(this).text());
$('#modal_login').show();
});
$('#modal_login span.close').click(function() {
$('#modal_login').hide();
});
$('#_login').click(function() {
_passphrase = $("#text_passphrase").val();
if(_passphrase) {
_login();
$('#modal_login').hide();
}
});
$('#btn_tweet').click(function() {
$('#modal_tweet').show();
});
$('#modal_tweet span.close').click(function() {
$('#modal_tweet').hide();
});
$('#_tweet').click(function() {
if($('#tweet_message').val().length == 0)
return;
send_tweet();
$("#modal_tweet").hide();
});
$('#_retweet').click(function() {
if($('#retweet_message').val().length == 0)
return;
send_retweet();
$("#modal_retweet").hide();
});
function _show_reply_modal(ele) {
//alert(ele.getAttribute("data-recipient"));
var recipient = ele.getAttribute("data-recipient");
$('#tweet_reply').val("");
$("#reply_name").text("");
$("#reply_account").text(recipient);
$("#reply_account").show();
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': recipient },
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#reply_name').text(name).append("<span class='account_note' style='font-size:80%;color:#999;'> (" + recipient + ") </span>");
$("#reply_account").hide();
}
}
});
$("#modal_reply").show();
}
function _show_retweet_modal(ele) {
//alert(ele.getAttribute("data-recipient"));
var retweet_from = ele.getAttribute("data-from");
$("#retweet_from_name").text("");
$("#retweet_from_account").text(retweet_from);
$("#retweet_from_account").show();
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': retweet_from },
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#retweet_from_name').text(name).append("<span class='account_note' style='font-size:80%;color:#999;'> (" + retweet_from + ") </span>");
$("#retweet_from_account").hide();
}
$('#retweet_message').val("RT "+ String(name) + "(" + $("#retweet_from_account").text() + "): " +$("#"+ ele.getAttribute("data-id") + " .message_content").text());
}
});
$("#modal_retweet").show();
}
$('#modal_reply span.close').click(function() {
$('#modal_reply').hide();
});
$('#modal_retweet span.close').click(function() {
$('#modal_retweet').hide();
});
$('#_reply').click(function() {
if($('#tweet_reply').val().length == 0)
return;
send_reply();
$("#modal_reply").hide();
});
window.onclick = function(event) {
if (event.target.className == 'modal') {
event.target.style.display = "none";
}
}
</script>
<script>
var VERSION = 'v0.0.1';
var MAX_MESSAGES = 500;
var FEE_BITS = 0.0001;
var REFRESH_TIMS = 30;
var AUTO_LOGIN = true;
var _passphrase_key = window.location.href + '_' + VERSION;
var _node_url = "http://127.0.0.1:27876/nxt";
var _current_login_account;
var _passphrase;
var _current_channel_name = "about";
var _last_message_timestamp = 0;
var _current_direct_message_recipient;
var entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
function _login() {
$.ajax({url: _node_url, data: {'requestType': 'getAccountId', 'secretPhrase': _passphrase },
success: function(data) {
_current_login_account = $.parseJSON(data)["accountRS"];
$("#current_login_account").text(_current_login_account);
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': _current_login_account },
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#current_login_name').text(name);
}else {
$('#current_login_name').text('- No Name -');
}
$("#btn_login").text('Change User');
}
});
_current_channel_name = 'home';
$(".extra_about").hide();
show_messages();
_show_metas();
if(localStorage && AUTO_LOGIN){ localStorage.setItem(_passphrase_key, _passphrase); }
$("#btn_tweet").show();
},
error: function() {
show_error('error login');
}
});
}
function _show_sender_name(account, id) {
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': account },
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#'+id+" span.sender").text(name).append("<span class='account_note'> (" + account + ") </span>");
}
}
});
}
function _show_at_reply_name(account, id) {
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': account },
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#'+id+" .message_body span.at_reply").text('@' + name + ': ');
}
}
});
}
function _show_metas() {
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'setter': _current_login_account, 'property': 'following', 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
if(mgs[0])
_current_direct_message_recipient = _current_direct_message_recipient || mgs[0]['recipientRS'];
$("#meta_following").text(" (" + mgs.length +")");
}
});
$.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'recipient': _current_login_account, 'property': 'following', 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
$("#meta_followers").text(" (" + mgs.length +")");
}
});
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': _current_login_account, 'otherAccount': _current_login_account, 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
$("#meta_tweets").text(" (" + mgs.length +")");
}
});
$.ajax({url: _node_url, data: {'requestType': 'getBalance', 'chain': 4, 'account': _current_login_account},
success: function(data) {
var mgs = $.parseJSON(data)["unconfirmedBalanceNQT"];
$("#account_balance").text("" + Number((mgs/100000000)).toFixed(4) +" BITS");
}
});
}
function show_home() {
if(!_current_login_account)
return;
var following = [_current_login_account];
var all_messages = [];
var s1 = $.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'setter': _current_login_account, 'property': 'following', }, async: false,
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
for(var i=0;i<mgs.length;i++){
following.push(mgs[i]['recipientRS']);
}
}
});
for(var i=0; i<following.length; i++) {
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': following[i], 'lastIndex': MAX_MESSAGES }, async: false,
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['isText'] && mgs[i]['message']) {
all_messages.push(mgs[i]);
}
}
}
});
}
//console.log(all_messages);
all_messages = all_messages.sort(function(a,b){ return b['transactionTimestamp'] - a['transactionTimestamp']});
if($("div.messages .message").length > 0 && all_messages.length > 0) {
if( all_messages[0]['transactionTimestamp'] <= _last_message_timestamp)
return;
}
$("div.messages").empty();
for(var i=0; i<all_messages.length; i++) {
var mgs = all_messages;
if($("#"+mgs[i]['transactionTimestamp']).length > 0)
continue;
var html = build_message_tag(mgs[i]);
$("div.messages").append(html);
_show_sender_name(mgs[i]['senderRS'], mgs[i]['transactionTimestamp']);
_show_at_reply_name(mgs[i]['recipientRS'], mgs[i]['transactionTimestamp']);
if(_last_message_timestamp > 0 && mgs[i]['transactionTimestamp'] > _last_message_timestamp)
$("#"+mgs[i]['transactionTimestamp']).addClass('new_message');
}
if(all_messages[0])
_last_message_timestamp = all_messages[0]['transactionTimestamp'];
$("a.channel").removeClass('selected_channel');
$("#channel_home").addClass('selected_channel');
}
function show_followers() {
$("div.messages").empty();
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'recipient': _current_login_account, 'property': 'following', 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['setterRS']) {
var _message = "<div class='message' id='" + mgs[i]['setterRS'] +"'><div class='message_header'><span class='sender at_reply'>" +
mgs[i]['setterRS'] + "</span><span class='datatime'> " + "</span></div><div class='message_body'><p align='right'></p>" + "</div></div>";
$("div.messages").append(_message);
_show_sender_name(mgs[i]['setterRS'], mgs[i]['setterRS']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_followers").addClass('selected_channel');
//$("div.messages").animate({scrollTop: $("div.messages").prop("scrollHeight") }, 10);
},
error: function() {
show_error('error fecthing followers');
}
});
}
function show_following() {
$("div.messages").empty();
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'setter': _current_login_account, 'property': 'following', 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['recipientRS']) {
var _message = build_following_tag(mgs[i]);
$("div.messages").append(_message);
_show_sender_name(mgs[i]['recipientRS'], mgs[i]['recipientRS']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_following").addClass('selected_channel');
//$("div.messages").animate({scrollTop: $("div.messages").prop("scrollHeight") }, 10);
},
error: function() {
show_error('error fecthing following');
}
});
}
function show_direct_messages() {
$("div.direct_messages").empty();
if(!_current_login_account)
return;
var direct_message_recipients = [];
$.ajax({url: _node_url, data: {'requestType': 'getAccountProperties', 'chain': 4, 'setter': _current_login_account, 'property': 'following', 'lastIndex': MAX_MESSAGES }, async: false,
success: function(data) {
var mgs = $.parseJSON(data)["properties"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['recipientRS']) {
direct_message_recipients.push(mgs[i]['recipientRS']);
}
}
$("#direct_message_recipient").empty();
for(var i=0;i<direct_message_recipients.length;i++) {
$("#direct_message_recipient").append($('<option>', {
value: direct_message_recipients[i],
text: direct_message_recipients[i],
id: "opt_" + direct_message_recipients[i],
selected: _current_direct_message_recipient == direct_message_recipients[i]
}));
$.ajax({url: _node_url, data: {'requestType': 'getAccount', 'account': direct_message_recipients[i] }, async: false,
success: function(data) {
var name = $.parseJSON(data)["name"];
if (name && name.length > 0) {
$('#opt_'+ direct_message_recipients[i]).text(name).append(" (" + direct_message_recipients[i] + ")");
}
}
});
}
},
error: function() {
show_error('error fecthing following');
}
});
//_current_direct_message_recipient = _current_direct_message_recipient || direct_message_recipients[direct_message_recipients.length - 1];
if(!_current_direct_message_recipient)
return;
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': _current_login_account, 'otherAccount': _current_direct_message_recipient,
'secretPhrase': _passphrase, 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
for(var i=mgs.length-1;i>=0;i--){
if(mgs[i]['decryptedMessage'] && mgs[i]['encryptedMessageIsText']) {
var html = build_direct_message_tag(mgs[i]);
$("div.direct_messages").append(html);
_show_sender_name(mgs[i]['senderRS'], mgs[i]['transactionTimestamp']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_direct_messages").addClass('selected_channel');
//$("div.main").animate({scrollTop: $("div.main").prop("scrollHeight") }, 10);
},
error: function() {
show_error('error fecthing direct messages');
}
});
show_unconfirm_direct_messages();
}
function show_unconfirm_direct_messages() {
$("div.unconfirmed_direct_messages").empty();
if(!_current_login_account)
return;
if(_current_channel_name != 'direct_messages')
return;
$.ajax({url: _node_url, data: {'requestType': 'getUnconfirmedTransactions', 'chain': 4, 'account': _current_login_account, 'account': _current_direct_message_recipient, 'lastIndex': MAX_MESSAGES}, async: false,
success: function(data) {
var rtn_msg = $.parseJSON(data);
for(var i = 0; i<rtn_msg['unconfirmedTransactions'].length; i++) {
var msg = rtn_msg['unconfirmedTransactions'][i];
if(msg && msg['attachment']['encryptedMessage'] && msg['attachment']['encryptedMessage']['isText']) {
//if(msg['senderRS'] == _current_login_account || msg['recipientRS'] == _current_login_account) {
if(msg['senderRS'] == _current_login_account || msg['senderRS'] == _current_direct_message_recipient) {
$.ajax({url: _node_url, data: {'requestType': 'decryptFrom', 'account': _current_direct_message_recipient, 'data': msg['attachment']['encryptedMessage']['data'], 'nonce': msg['attachment']['encryptedMessage']['nonce'], 'decryptedMessageIsText': true, 'secretPhrase': _passphrase }, async: false,
success: function(data) {
var message = $.parseJSON(data)["decryptedMessage"];
if (message) {
msg['attachment']['message'] = message;
var html = build_unconfirm_direct_message_tag(msg);
//if($("#"+msg['attachment']['encryptedMessageHash']).length == 0)
$("div.unconfirmed_direct_messages").append(html);
_show_sender_name(msg['senderRS'], msg['attachment']['encryptedMessageHash']);
}
}
});
}
}
}
}
});
$("div._direct_messages").animate({scrollTop: $("div._direct_messages").prop("scrollHeight") + 9999} , 10);
}
function show_at_me() {
$("div.messages").empty();
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': _current_login_account, 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['isText'] && mgs[i]['message'] && mgs[i]['recipientRS'] == _current_login_account && mgs[i]['senderRS'] != _current_login_account) {
var html = build_message_tag(mgs[i]);
$("div.messages").append(html);
_show_at_reply_name(mgs[i]['recipientRS'], mgs[i]['transactionTimestamp']);
_show_sender_name(mgs[i]['senderRS'], mgs[i]['transactionTimestamp']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_at_me").addClass('selected_channel');
},
error: function() {
show_error('error fecthing replies to me');
}
});
}
function show_tweets() {
$("div.messages").empty();
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': _current_login_account, 'otherAccount': _current_login_account, 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['isText'] && mgs[i]['message']) {
var html = build_message_tag(mgs[i]);
$("div.messages").append(html);
_show_sender_name(mgs[i]['senderRS'], mgs[i]['transactionTimestamp']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_tweets").addClass('selected_channel');
//$("div.messages").animate({scrollTop: $("div.messages").prop("scrollHeight") }, 10);
},
error: function() {
show_error('error fecthing tweets');
}
});
}
function show_tweets_replies() {
$("div.messages").empty();
if(!_current_login_account)
return;
$.ajax({url: _node_url, data: {'requestType': 'getPrunableMessages', 'chain': 4, 'account': _current_login_account, 'lastIndex': MAX_MESSAGES },
success: function(data) {
var mgs = $.parseJSON(data)["prunableMessages"];
for(var i=0;i<mgs.length;i++){
if(mgs[i]['isText'] && mgs[i]['message']) {
if(mgs[i]['senderRS'] != _current_login_account)
continue;
var html = build_message_tag(mgs[i]);
$("div.messages").append(html);
_show_at_reply_name(mgs[i]['recipientRS'], mgs[i]['transactionTimestamp']);
_show_sender_name(mgs[i]['senderRS'], mgs[i]['transactionTimestamp']);
}
}
$("a.channel").removeClass('selected_channel');
$("#channel_tweets_replies").addClass('selected_channel');
},
error: function() {
show_error('error fecthing tweets and replies');
}
});
}
function show_messages() {
_show_metas();
switch(_current_channel_name) {
case 'tweets':
show_tweets();
break;
case 'tweets_replies':
show_tweets_replies();
break;
case 'direct_messages':
show_direct_messages();
break;
case 'following':
show_following();
break;
case 'followers':
show_followers();
break;
case 'home':
show_home();
break;
case 'at_me':
show_at_me();
break;
}
}
function show_unconfirm_messages() {
$('div.unconfirmed_messages').empty();
if(!_current_login_account)
return;
if(_current_channel_name == 'home' || _current_channel_name == 'tweets' || _current_channel_name == 'tweets_replies') {
$.ajax({url: _node_url, data: {'requestType': 'getUnconfirmedTransactions', 'chain': 4, 'account': _current_login_account, 'lastIndex': MAX_MESSAGES},
success: function(data) {
var rtn_msg = $.parseJSON(data);
for(var i = rtn_msg['unconfirmedTransactions'].length - 1; i>=0; i--) {
var msg = rtn_msg['unconfirmedTransactions'][i];
if(msg && msg['attachment']['messageIsText']) {
//if(msg['senderRS'] == _current_login_account || msg['recipientRS'] == _current_login_account) {
if(msg['senderRS'] == _current_login_account) {
var html = build_unconfirm_message_tag(msg);
$("div.unconfirmed_messages").append(html);
_show_at_reply_name(msg['recipientRS'], msg['attachment']['messageHash']);
_show_sender_name(msg['senderRS'], msg['attachment']['messageHash']);
}
}
}
}
});
}
}
function show_notice(msg) {
$('.notify .text').text(msg);
$('.notify').removeClass('error');
$('.notify').addClass('notice');
$('.notify').show();
}
function show_error(msg) {
$('.notify .text').text(msg);
$('.notify').removeClass('notice');
$('.notify').addClass('error');
$('.notify').show();
}
function _send_message(msg, recipient, type = 'tweet') {
if(msg.length == 0)
return;
var mini_fee = FEE_BITS*100000000;
$.ajax({url: _node_url, data: {'requestType': 'sendMessage', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'broadcast': false,
'message': msg, 'messageIsText': true, 'messageIsPrunable': true
}, type: 'POST', async: false,
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error sending message: ' + rtn_msg['errorDescription']);
}else {
mini_fee = rtn_msg["transactionJSON"]["feeNQT"];
$.ajax({url: _node_url, data: {'requestType': 'sendMessage', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'feeNQT': mini_fee, ////////////////////////////////////////////////////////////////////////////////////////////////////////
'message': msg, 'messageIsText': true, 'messageIsPrunable': true
}, type: 'POST',
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error sending message: ' + rtn_msg['errorDescription']);
} else {
if(rtn_msg["transactionJSON"]) {
$('#' + type + '_message').val("");
//show_notice("Message Sent at " + (new Date(rtn_msg["transactionJSON"]['timestamp']*1000 + Date.UTC(2018))).toTimeString().split(' ')[0] + ".");
show_unconfirm_messages();
}
}
},
error: function() {
show_error('error sending messages');
}
});
}
}
});
}
function send_tweet() {
_send_message($("#tweet_message").val(), _current_login_account);
}
function send_retweet() {
_send_message($("#retweet_message").val(), _current_login_account);
}
function send_reply() {
var recipient = $("#reply_account").text();
_send_message($("#tweet_reply").val(), recipient);
}
$("a.channel").click(function() {
$("a.channel").removeClass('selected_channel');
_current_channel_address = this.getAttribute("id");
_current_channel_name = this.getAttribute("data-channel-name");
$("div.messages").empty();
$(".fixed_content").hide();
$(".extra_"+_current_channel_name).show();
_last_message_timestamp = 0;
show_messages();
$(this).addClass('selected_channel');
//$('div.unconfirmed_messages').empty();
//if(_current_channel_name == 'direct_messages')
// $("div.main").animate({scrollTop: $("div.main").prop("scrollHeight") }, 10);
});
$("#direct_message_recipient").change(function() {
_current_direct_message_recipient = $(this).val();
show_direct_messages();
//$("div.main").animate({scrollTop: $("div.main").prop("scrollHeight") }, 10);
});
$("#_following").click(function() {
var mini_fee = FEE_BITS*100000000;
var recipient = $("#following_account").val();
if(recipient.length == 0)
return;
$.ajax({url: _node_url, data: {'requestType': 'setAccountProperty', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'broadcast': false,
'property': 'following', 'value': 'true'
}, type: 'POST', async: false,
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error request following: ' + rtn_msg['errorDescription']);
} else {
mini_fee = rtn_msg["transactionJSON"]["feeNQT"];
$.ajax({url: _node_url, data: {'requestType': 'setAccountProperty', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'feeNQT': mini_fee,
'property': 'following', 'value': 'true'
}, type: 'POST',
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error request following: ' + rtn_msg['errorDescription']);
} else {
if(rtn_msg["transactionJSON"]) {
$("#following_account").val("");
show_notice("Following " + recipient + " request sent at " + (new Date(rtn_msg["transactionJSON"]['timestamp']*1000 + Date.UTC(2018))).toTimeString().split(' ')[0] + ". Request will be done after around 60 senconds (block time).");
}
}
},
error: function() {
show_error('Error request following');
}
});
}
}
});
});
function send_direct_message() {
if(!_current_login_account)
return;
var msg = $("#_direct_message").val();
if(msg.length == 0)
return;
var mini_fee = FEE_BITS*100000000;
$.ajax({url: _node_url, data: {'requestType': 'sendMessage', 'chain': 4, 'recipient': _current_direct_message_recipient,
'secretPhrase': _passphrase, 'broadcast': false,
'messageToEncrypt': msg, 'messageToEncryptIsText': true, 'encryptedMessageIsPrunable': true
}, type: 'POST', async: false,
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error sending direct message: ' + rtn_msg['errorDescription']);
}else{
mini_fee = rtn_msg["transactionJSON"]["feeNQT"];
$.ajax({url: _node_url, data: {'requestType': 'sendMessage', 'chain': 4, 'recipient': _current_direct_message_recipient,
'secretPhrase': _passphrase, 'feeNQT': mini_fee,
'messageToEncrypt': msg, 'messageToEncryptIsText': true, 'encryptedMessageIsPrunable': true
}, type: 'POST',
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error sending direct message: ' + rtn_msg['errorDescription']);
} else {
if(rtn_msg["transactionJSON"]) {
$("#_direct_message").val("");
//show_notice("Message Sent at " + (new Date(rtn_msg["transactionJSON"]['timestamp']*1000 + Date.UTC(2018))).toTimeString().split(' ')[0] + ".");
show_unconfirm_direct_messages();
}
}
},
error: function() {
show_error('error sending direct messages');
}
});
}
}
});
}
function do_unfollow(ele) {
var recipient = ele.getAttribute('data-recipient');
var r = confirm("Unfollow " + recipient + " ?");
if (r == true) {
$.ajax({url: _node_url, data: {'requestType': 'deleteAccountProperty', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'broadcast': false,
'property': 'following'
}, type: 'POST', async: false,
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error request following: ' + rtn_msg['errorDescription']);
} else {
mini_fee = rtn_msg["transactionJSON"]["feeNQT"];
$.ajax({url: _node_url, data: {'requestType': 'deleteAccountProperty', 'chain': 4, 'recipient': recipient,
'secretPhrase': _passphrase, 'feeNQT': mini_fee,
'property': 'following'
}, type: 'POST',
success: function(data) {
var rtn_msg = $.parseJSON(data);
if(rtn_msg['errorDescription']) {
show_error('Error request unfollowing: ' + rtn_msg['errorDescription']);
} else {
if(rtn_msg["transactionJSON"]) {
$("#following_account").val("");
show_notice("Unfollowing " + recipient + " request sent at " + (new Date(rtn_msg["transactionJSON"]['timestamp']*1000 + Date.UTC(2018))).toTimeString().split(' ')[0] + ". Request will be done after around 60 senconds (block time).");
}
}
},
error: function() {
show_error('Error request unfollowing');
}
});
}
}
});
} else {
return;
}
}
$( document ).ready(function() {
if(localStorage && AUTO_LOGIN) {
_passphrase = localStorage.getItem(_passphrase_key);
if(_passphrase && _passphrase.length > 0) {
_login();
}
}
show_messages();
//show_unconfirm_messages();
setInterval(show_messages, REFRESH_TIMS*1000);
setInterval(show_unconfirm_messages, 10*1000);
});
function build_message_tag(mgs) {
var date = new Date(mgs['transactionTimestamp']*1000 + Date.UTC(2018));
var _message = `<div class='message' id='${mgs['transactionTimestamp']}'>
<div class='message_header'>
<span class='at_reply' data-recipient='${mgs['senderRS']}' onclick='_show_reply_modal(this)' style="float:right;font-size:90%;color:#999;"> Reply</span>
<span class='at_reply' data-from='${mgs['senderRS']}' data-id='${mgs['transactionTimestamp']}' onclick='_show_retweet_modal(this)' style="float:right;font-size:90%;color:#999;padding-right:10px;">Retweet </span>
<span class='sender at_reply ${mgs['senderRS']}' data-recipient='${mgs['senderRS']}' onclick='_show_reply_modal(this)'>${mgs['senderRS']}</span><span class='datatime'>${date.toLocaleString()}</span>
</div>
<div class='message_body'>
${ (mgs['senderRS'] != mgs['recipientRS']) ? `<span class='at_reply ${mgs['recipientRS']}' data-recipient='${mgs['recipientRS']}' onclick='_show_reply_modal(this)'>@${mgs['recipientRS']}: </span>` : '' }
<span class='message_content'>${escapeHtml(mgs['message'])}</span>
</div>
</div>`;
return _message;
}
function build_unconfirm_message_tag(mgs) {
//var date = new Date(mgs['timestamp']*1000 + Date.UTC(2018));
var _message = `<div class='message unconfirmed_message' id='${mgs['attachment']['messageHash']}'>
<div class='message_header'>
<span class='at_reply' style="float:right;font-size:90%;color:#ffcc00;"> Waiting for confirm</span>
<span class='sender' >${mgs['senderRS']}</span><span class='datatime'></span>
</div>
<div class='message_body'>
${ (mgs['senderRS'] != mgs['recipientRS']) ? `<span class='at_reply ${mgs['recipientRS']}' data-recipient='${mgs['recipientRS']}' >@${mgs['recipientRS']}: </span>` : '' }
<span class='message_content'>${escapeHtml(mgs['attachment']['message'])}</span>
</div>
</div>`;
return _message;
}
function build_direct_message_tag(mgs) {
var date = new Date(mgs['transactionTimestamp']*1000 + Date.UTC(2018));
var _message = `<div class='message direct_message ${(mgs['senderRS']==_current_login_account) ? 'self' : ''}' id='${mgs['transactionTimestamp']}'>
<div class='message_header'>
<span class='sender' >${mgs['senderRS']}</span><span class='datatime'></span>
<span class='datatime'>${date.toLocaleString()}</span>
</div>
<div class='message_body'>
<span class='message_content'>${escapeHtml(mgs['decryptedMessage'])}</span>
</div>
</div>`;
return _message;
}
function build_unconfirm_direct_message_tag(mgs) {
var _message = `<div class='message direct_message unconfirmed_message ${(mgs['senderRS']==_current_login_account) ? 'self' : ''}' id='${mgs['attachment']['encryptedMessageHash']}'>
<div class='message_header'>
<span class='at_reply' style="float:right;font-size:90%;color:#ffcc00;"> Waiting for confirm</span>
<span class='sender' >${mgs['senderRS']}</span><span class='datatime'></span>
</div>
<div class='message_body'>
<span class='message_content'>${escapeHtml(mgs['attachment']['message'])}</span>
</div>
</div>`;
return _message;
}
function build_following_tag(mgs) {
var _message = `<div class='message' id='${mgs['recipientRS']}'>
<div class='message_header'>
<span class='sender at_reply ${mgs['recipientRS']}' data-recipient='${mgs['recipientRS']}' onclick='_show_reply_modal(this)'>${mgs['recipientRS']}</span><span class='datatime'></span>
</div>
<div class='message_body'>
<div class='desc_content' style="float:left;"></div>
<p style='text-align:right;'><button class='unfollow' onclick='do_unfollow(this)' data-recipient='${mgs['recipientRS']}'>Unfollow</button></p>
</div>
</div>`;
return _message;
}
</script>
</html>