diff --git a/js/interface_common.js b/js/interface_common.js
index ec2acdd..4f513bc 100644
--- a/js/interface_common.js
+++ b/js/interface_common.js
@@ -119,6 +119,9 @@ function closeModal(req, switchMode) {
else
this.remove(); // if it's minimized it will be removed with twister.modal[i].drapper
+ if (typeof twister.modal[i].onClose === 'function')
+ twister.modal[i].onClose(twister.modal[i].closeArg);
+
twister.modal[i].drapper.remove();
twister.modal[i] = undefined;
}
@@ -731,9 +734,6 @@ function addPeerToFollowingList(list, peerAlias) {
}
function fillWhoToFollowModal(list, hlist, start) {
- var itemTmp = $('#follow-suggestion-template').clone(true)
- .removeAttr('id');
-
for (var i = 0; i < followingUsers.length && list.length < start + 20; i++) {
if (typeof twisterFollowingO.followingsFollowings[followingUsers[i]] !== 'undefined') {
for (var j = 0; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length && list.length < start + 25; j++) {
@@ -741,27 +741,11 @@ function fillWhoToFollowModal(list, hlist, start) {
if (followingUsers.indexOf(utf) < 0 && list.indexOf(utf) < 0) {
list.push(utf);
- var item = itemTmp.clone(true);
-
- item.find('.twister-user-info').attr('data-screen-name', utf);
- item.find('.twister-user-name').attr('href', $.MAL.userUrl(utf));
- item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followingUsers[i]));
- item.find('.twister-user-tag').text('@' + utf);
-
- getAvatar(utf, item.find('.twister-user-photo'));
- getFullname(utf, item.find('.twister-user-full'));
- getBioToElem(utf, item.find('.bio'));
- getFullname(followingUsers[i], item.find('.followed-by').text(followingUsers[i]));
- getStatusTime(utf, item.find('.latest-activity .time'));
-
- item.find('.twister-user-remove').remove();
-
- hlist.append(item);
+ processWhoToFollowSuggestion(hlist, utf, followingUsers[i]);
}
}
}
}
- itemTmp.remove();
if (i >= followingUsers.length - 1)
return false;
@@ -782,12 +766,36 @@ function openWhoToFollowModal() {
modal.content.on('scroll', function() {
if (modal.content.scrollTop() >= hlist.height() - modal.content.height() - 20) {
- if (!fillWhoToFollowModal(tmplist, hlist, tmplist.length))
+ if (!fillWhoToFollowModal(tmplist, modal.self, tmplist.length))
modal.content.off('scroll');
}
});
- fillWhoToFollowModal(tmplist, hlist, 0);
+ fillWhoToFollowModal(tmplist, modal.self, 0);
+}
+
+function openNewUsersModal() {
+ var modal = openModal({
+ classAdd: 'new-users-modal',
+ title: polyglot.t('New Users'),
+ onClose: function() {
+ NewUserSearch.isNewUserModalOpen = false;
+ }
+ });
+
+ var hlist = $('
')
+ .appendTo(modal.content);
+ var count = 15;
+
+ modal.content.on('scroll', function() {
+ if (modal.content.scrollTop() >= hlist.height() - modal.content.height() - 20) {
+ if (newUsers.getLastNUsers(5, count, modal.self))
+ count += 5;
+ }
+ });
+
+ NewUserSearch.isNewUserModalOpen = true;
+ newUsers.getLastNUsers(15, 0, modal.self);
}
function openModalUriShortener()
@@ -1237,6 +1245,8 @@ function loadModalFromHash() {
openWhoToFollowModal();
else if (hashstring === '#/uri-shortener')
openModalUriShortener();
+ else if (hashstring === '#newusers')
+ openNewUsersModal();
}
function initHashWatching() {
diff --git a/js/interface_home.js b/js/interface_home.js
index 5b1984f..03116ec 100644
--- a/js/interface_home.js
+++ b/js/interface_home.js
@@ -100,6 +100,11 @@ var InterfaceFunctions = function() {
else
killInterfaceModule('who-to-follow');
+ if ($.Options.NewUsers.val === 'enable')
+ initNewUsers();
+ else
+ killInterfaceModule('new-users');
+
if ($.Options.TwistdayReminder.val === 'enable')
initTwistdayReminder();
else
@@ -113,7 +118,7 @@ var InterfaceFunctions = function() {
if ($.Options.WebTorrent.val === 'enable')
initWebTorrent();
}
-}
+};
function initTopTrends() {
var $tt = initInterfaceModule('toptrends');
@@ -200,6 +205,30 @@ function refreshWhoToFollow() {
}
}
+function initNewUsers() {
+ var nus = initInterfaceModule('new-users');
+
+ newUsers = NewUserSearch();
+ if (nus.length) {
+ var nusRefresh = nus.find('.refresh-users');
+ nusRefresh.on('click', refreshNewUsers);
+ setTimeout(function() {nusRefresh.click();}, 100);
+ }
+}
+
+function refreshNewUsers() {
+ var module = $('.module.new-users');
+ var list = module.find('.follow-suggestions');
+
+ if (list.length) {
+ list.empty().hide();
+ module.find('.refresh-users').hide();
+ module.find('.loading-roller').show();
+
+ newUsers.getLastNUsers(3, 0, module, true);
+ }
+}
+
function initTwistdayReminder() {
var $module = initInterfaceModule('twistday-reminder');
diff --git a/js/interface_localization.js b/js/interface_localization.js
index bef7976..f3ee644 100644
--- a/js/interface_localization.js
+++ b/js/interface_localization.js
@@ -372,7 +372,9 @@ if(preferredLanguage == "en"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
if(preferredLanguage == "es"){
@@ -717,7 +719,9 @@ if(preferredLanguage == "es"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1061,7 +1065,9 @@ if(preferredLanguage == "uk"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1410,7 +1416,9 @@ if(preferredLanguage == "zh-CN"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1756,7 +1764,9 @@ if(preferredLanguage == "nl"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2100,7 +2110,9 @@ if(preferredLanguage == "it"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2445,7 +2457,9 @@ if(preferredLanguage == "fr"){
"users_favs": "Favorites of @%{username}",
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2797,7 +2811,9 @@ if(preferredLanguage == "ru"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -3145,7 +3161,9 @@ if(preferredLanguage == "de"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -3488,7 +3506,9 @@ if(preferredLanguage == "ja"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -3837,7 +3857,9 @@ if(preferredLanguage == "pt-BR"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -4182,7 +4204,9 @@ if(preferredLanguage == "tr"){
"Favorites": "Favoriler",
"You have to log in to favorite messages.": "İletileri favorine eklemek için giriş yapmalısın.",
"fav_this": "Sana özel mi?",
- "Last activity": "Son etkinlik"
+ "Last activity": "Son etkinlik",
+ "New Users": "Yeni Kullanıcılar",
+ "Live tracking" : "Canlı takip"
};
}
@@ -4530,7 +4554,9 @@ if(preferredLanguage == "cs"){
"Favorites": "Favorites",
"You have to log in to favorite messages.": "You have to log in to favorite messages.",
"fav_this": "Is it for you only?",
- "Last activity": "Last activity"
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
diff --git a/js/options.js b/js/options.js
index 2acd553..84f17cb 100644
--- a/js/options.js
+++ b/js/options.js
@@ -41,6 +41,17 @@ function twisterOptions() {
name: 'WhoToFollow',
valDefault: 'enable'
});
+ this.add({
+ name: 'NewUsers',
+ valDefault: 'enable',
+ tickMethod: function (elem) {
+ $('#NewUsersCont').css('display', (elem.value === 'enable') ? 'block' : 'none');
+ }
+ });
+ this.add({
+ name: 'NewUsersLiveTracking',
+ valDefault: 'enable'
+ });
this.add({
name: 'TwistdayReminder',
valDefault: 'enable',
diff --git a/js/twister_following.js b/js/twister_following.js
index c736b05..f0a700a 100644
--- a/js/twister_following.js
+++ b/js/twister_following.js
@@ -17,6 +17,7 @@ var _lastSearchUsersResultsRemovedFromDHTgetQueue = true;
var _lastLoadFromDhtTime = 0;
var twisterFollowingO = undefined;
+var newUsers = undefined;
var TwisterFollowing = function (user) {
if (!(this instanceof TwisterFollowing))
@@ -427,6 +428,127 @@ function followingEmptyOrMyself() {
return (!followingUsers.length || (followingUsers.length === 1 && followingUsers[0] === defaultScreenName))
}
+/* NEW USER SEARCH */
+var NewUserSearch = function(){
+ if (!(this instanceof NewUserSearch))
+ return new NewUserSearch();
+
+ this.init();
+};
+
+NewUserSearch.knownNewUsers = [];
+NewUserSearch.isNewUserThRunning = false;
+NewUserSearch.isNewUserModalOpen = false;
+NewUserSearch.startProcessedBlock = -1;
+NewUserSearch.lastProcessedBlock = -1;
+NewUserSearch.processBlockUsersProxy = function(block, args){
+ if (args.obj instanceof NewUserSearch)
+ args.obj.processBlockUsers(block, args);
+};
+NewUserSearch.live = function(module) {
+ newUsers.getNewUsers(module);
+};
+NewUserSearch.processBestBlockUsersProxy = function(block, args){
+ if (block.height > NewUserSearch.startProcessedBlock) {
+ if (args.obj instanceof NewUserSearch)
+ args.obj.processBlockUsers(block, {obj: args.obj, args: {n: 0, offset: 0, module: args.args.module, prepend: true, live: true}});
+ }
+};
+
+NewUserSearch.prototype = {
+ storage: undefined,
+ isForced: false,
+
+ init: function() {
+ this.storage = $.initNamespaceStorage(defaultScreenName).sessionStorage;
+ if (this.storage.isSet("knownNewUsers"))
+ NewUserSearch.knownNewUsers = this.storage.get("knownNewUsers");
+ if (this.storage.isSet("lastProcessedBlock"))
+ NewUserSearch.lastProcessedBlock = this.storage.get("lastProcessedBlock");
+ if (this.storage.isSet("startProcessedBlock"))
+ NewUserSearch.startProcessedBlock = this.storage.get("startProcessedBlock");
+
+ if ($.Options.NewUsersLiveTracking.val === 'enable')
+ setInterval(function(){NewUserSearch.live($('.module.new-users'));}, 10000);
+ },
+
+ save: function(){
+ this.storage.set("knownNewUsers", NewUserSearch.knownNewUsers);
+ this.storage.set("lastProcessedBlock", NewUserSearch.lastProcessedBlock);
+ this.storage.set("startProcessedBlock", NewUserSearch.startProcessedBlock);
+ },
+
+ getNewUsers: function(module) {
+ requestBestBlock(NewUserSearch.processBestBlockUsersProxy, {obj: this, args: {module: module}});
+ },
+
+ getLastNUsers: function (n, offset, module, forced) {
+ for (var i = offset; i < NewUserSearch.knownNewUsers.length && i < offset + n; i++)
+ processWhoToFollowSuggestion(module, NewUserSearch.knownNewUsers[i]);
+
+ if (NewUserSearch.knownNewUsers.length >= n + offset) {
+ NewUserSearch.isNewUserThRunning = false;
+ return true;
+ }
+
+ if (NewUserSearch.isNewUserThRunning)
+ return false;
+
+ NewUserSearch.isNewUserThRunning = true;
+ this.isForced = forced;
+
+ if (NewUserSearch.lastProcessedBlock == -1)
+ requestBestBlock(NewUserSearch.processBlockUsersProxy, {obj: this, args: {n: n, offset: offset, module: module}});
+ else
+ requestNthBlock(NewUserSearch.lastProcessedBlock - 1, NewUserSearch.processBlockUsersProxy, {obj: this, args: {n: n, offset: offset, module: module}});
+
+ return true;
+ },
+
+ processBlockUsers: function (block, args) {
+ if (NewUserSearch.startProcessedBlock === -1)
+ NewUserSearch.startProcessedBlock = block.height;
+ if (NewUserSearch.lastProcessedBlock === -1 || block.height < NewUserSearch.lastProcessedBlock)
+ NewUserSearch.lastProcessedBlock = block.height;
+
+ if ((this.isForced || NewUserSearch.isNewUserModalOpen) &&
+ NewUserSearch.knownNewUsers.length + block.usernames.length < args.args.n + args.args.offset &&
+ typeof block.previousblockhash !== 'undefined') {
+
+ setTimeout(function () {
+ requestBlock(block.previousblockhash, NewUserSearch.processBlockUsersProxy, {obj: args.obj, args: args.args});
+ }, 10);
+
+ } else {
+ NewUserSearch.isNewUserThRunning = false;
+ this.isForced = false;
+ }
+
+ var i = 0;
+ for (; i < block.usernames.length; i++) {
+ if (NewUserSearch.knownNewUsers.indexOf(block.usernames[i]) == -1) {
+ processWhoToFollowSuggestion(args.args.module, block.usernames[i], undefined, args.args.prepend);
+ if (args.args.prepend)
+ NewUserSearch.knownNewUsers.unshift(block.usernames[i]);
+ else
+ NewUserSearch.knownNewUsers.push(block.usernames[i]);
+ if (!args.args.live && NewUserSearch.knownNewUsers.length >= args.args.n + args.args.offset)
+ break;
+ }
+ }
+ for (; i < block.usernames.length; i++) {
+ if (NewUserSearch.knownNewUsers.indexOf(block.usernames[i]) == -1) {
+ if (args.args.prepend)
+ NewUserSearch.knownNewUsers.unshift(block.usernames[i]);
+ else
+ NewUserSearch.knownNewUsers.push(block.usernames[i]);
+ }
+ }
+
+ this.save();
+ }
+};
+
// randomly choose a user we follow, get "following1" from him and them
// choose a suggestion from their list. this function could be way better, but
// that's about the simplest we may get to start with.
@@ -446,10 +568,11 @@ function getRandomFollowSuggestion() {
var suggested = false;
var j = Math.floor(Math.random() * twisterFollowingO.followingsFollowings[followingUsers[i]].following.length);
+ var module = $('.module.who-to-follow');
for( ; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length; j++ ) {
if( followingUsers.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0 &&
_followSuggestions.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0) {
- processWhoToFollowSuggestion(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j], followingUsers[i]);
+ processWhoToFollowSuggestion(module, twisterFollowingO.followingsFollowings[followingUsers[i]].following[j], followingUsers[i]);
_followSuggestions.push(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]);
suggested = true;
break;
@@ -501,28 +624,46 @@ function getWhoFollows(peerAlias, elem) {
;
}
-function processWhoToFollowSuggestion(suggestion, followedBy) {
+function processWhoToFollowSuggestion(module, suggestion, followedBy, prepend) {
if (suggestion) {
- var module = $('.module.who-to-follow');
var list = module.find('.follow-suggestions');
var item = $('#follow-suggestion-template').clone(true)
.removeAttr('id');
item.find('.twister-user-info').attr('data-screen-name', suggestion);
item.find('.twister-user-name').attr('href', $.MAL.userUrl(suggestion));
- item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followedBy));
item.find('.twister-user-tag').text('@' + suggestion);
getAvatar(suggestion, item.find('.twister-user-photo'));
- getFullname(followedBy, item.find('.followed-by').text(followedBy));
getStatusTime(suggestion, item.find('.latest-activity .time'));
- item.find('.twister-user-remove').on('click', function() {
- item.remove();
- getRandomFollowSuggestion();
- });
+ if (module.hasClass('who-to-follow') || module.hasClass('who-to-follow-modal')) {
+ item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followedBy));
+ getFullname(followedBy, item.find('.followed-by').text(followedBy));
+ item.find('.twister-user-remove').on('click', function () {
+ item.remove();
+ getRandomFollowSuggestion();
+ });
+ }
+ else if (module.hasClass('new-users') || module.hasClass('new-users-modal')){
+ item.find('.followers').remove();
+ item.find('.twister-user-remove').remove();
+ }
+
+ if (module.hasClass('modal-wrapper')) {
+ getFullname(suggestion, item.find('.twister-user-full'));
+ getBioToElem(suggestion, item.find('.bio'));
+ item.find('.twister-user-remove').remove();
+ }
+
+ if (prepend)
+ list.prepend(item).show();
+ else
+ list.append(item).show();
+
+ while (module.hasClass('new-users') && list.children().length > 3)
+ list.children().last().remove();
- list.append(item).show();
module.find('.refresh-users').show();
module.find('.loading-roller').hide();
} else
diff --git a/js/twister_network.js b/js/twister_network.js
index 38694f7..bbfb2df 100644
--- a/js/twister_network.js
+++ b/js/twister_network.js
@@ -146,46 +146,56 @@ function requestBestBlock(cbFunc, cbArg) {
}, {});
}
+function requestNthBlock(n, cbFunc, cbArg) {
+ twisterRpc("getblockhash", [n],
+ function(args, hash) {
+ requestBlock(hash, args.cbFunc, args.cbArg);
+ }, {cbFunc:cbFunc, cbArg:cbArg},
+ function(args, ret) {
+ console.log("getblockhash error");
+ }, {});
+}
+
function requestBlock(hash, cbFunc, cbArg) {
twisterRpc("getblock", [hash],
function(args, block) {
- twisterdLastBlockTime = block.time;
- $(".last-block-time").text( timeGmtToText(twisterdLastBlockTime) );
-
if( args.cbFunc )
- args.cbFunc(args.cbArg);
+ args.cbFunc(block, args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg},
function(args, ret) {
console.log("requestBlock error");
}, {});
}
-
function networkUpdate(cbFunc, cbArg) {
requestNetInfo(function () {
- requestBestBlock(function(args) {
+ requestBestBlock(function(block, args) {
+
+ twisterdLastBlockTime = block.time;
+ $(".last-block-time").text(timeGmtToText(twisterdLastBlockTime));
+
var curTime = new Date().getTime() / 1000;
- if( twisterdConnections ) {
- if( twisterdLastBlockTime > curTime + 3600 ) {
+ if (twisterdConnections) {
+ if (twisterdLastBlockTime > curTime + 3600) {
$.MAL.setNetworkStatusMsg(polyglot.t("Last block is ahead of your computer time, check your clock."), false);
twisterdConnectedAndUptodate = false;
- } else if( twisterdLastBlockTime > curTime - (2 * 3600) ) {
- if( twisterDhtNodes ) {
+ } else if (twisterdLastBlockTime > curTime - (2 * 3600)) {
+ if (twisterDhtNodes) {
$.MAL.setNetworkStatusMsg(polyglot.t("Block chain is up-to-date, twister is ready to use!"), true);
twisterdConnectedAndUptodate = true;
- } else {
+ } else {
$.MAL.setNetworkStatusMsg(polyglot.t("DHT network down."), false);
twisterdConnectedAndUptodate = true;
- }
+ }
} else {
- var daysOld = (curTime - twisterdLastBlockTime) / (3600*24);
- $.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", { days: daysOld.toFixed(2) }), false);
+ var daysOld = (curTime - twisterdLastBlockTime) / (3600 * 24);
+ $.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", {days: daysOld.toFixed(2)}), false);
// don't alarm user if blockchain is just a little bit behind
twisterdConnectedAndUptodate = (daysOld < 2);
}
}
- if( args.cbFunc )
- args.cbFunc(args.cbArg)
+ if (args.cbFunc)
+ args.cbFunc(args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg} );
});
}
diff --git a/options.html b/options.html
index 8338e62..a915fbc 100644
--- a/options.html
+++ b/options.html
@@ -353,6 +353,26 @@