You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
872 lines
32 KiB
872 lines
32 KiB
// twister_following.js |
|
// 2013 Miguel Freitas |
|
// |
|
// Manage list of following users. Load/Save to localstorage and DHT. |
|
// Provides random user suggestions to follow. |
|
|
|
var followingUsers = []; |
|
var _isFollowPublic = {}; |
|
var _followsPerPage = 200; |
|
var _maxFollowingPages = 50; |
|
var _followingSeqNum = 0; |
|
var _followSuggestions = []; |
|
var _searchingPartialUsers = ""; |
|
var _searchKeypressTimer = undefined; |
|
var _lastSearchUsersResults = []; |
|
var _lastLoadFromDhtTime = 0; |
|
|
|
var twisterFollowingO = undefined; |
|
|
|
var TwisterFollowing = function (user) { |
|
if (!(this instanceof TwisterFollowing)) |
|
return new TwisterFollowing(user); |
|
|
|
this.init(user); |
|
}; |
|
|
|
TwisterFollowing.minUpdateInterval = 43200; // 1/2 day |
|
TwisterFollowing.maxUpdateInterval = 691200; // 8 days |
|
|
|
TwisterFollowing.prototype = { |
|
user: undefined, |
|
init: function (user) { |
|
this.user = user; |
|
this.load(); |
|
this.update(); |
|
}, |
|
knownFollowers: [], |
|
knownFollowersResetTime: new Date().getTime() / 1000, |
|
notFollowers: [], |
|
/* |
|
followinsFollowings = { |
|
"username": { |
|
"lastUpdate": <updatetime>, |
|
"updateInterval": <updateinterval>, |
|
"following": [] |
|
} |
|
} |
|
*/ |
|
followingsFollowings: {}, |
|
|
|
load: function () { |
|
var ns = $.initNamespaceStorage(this.user); |
|
|
|
if (ns.localStorage.isSet("followingsFollowings")) |
|
this.followingsFollowings = ns.localStorage.get("followingsFollowings"); |
|
|
|
if (ns.localStorage.isSet("knownFollowersResetTime")) |
|
this.knownFollowersResetTime = ns.localStorage.get("knownFollowersResetTime"); |
|
|
|
var ctime = new Date().getTime() / 1000; |
|
if (ctime - this.knownFollowersResetTime < TwisterFollowing.maxUpdateInterval && |
|
ns.localStorage.isSet("knownFollowers")) { |
|
this.knownFollowers = ns.localStorage.get("knownFollowers"); |
|
} else { |
|
this.knownFollowers = []; |
|
this.knownFollowersResetTime = ctime; |
|
ns.localStorage.set("knownFollowersResetTime", this.knownFollowersResetTime); |
|
} |
|
|
|
if (ns.sessionStorage.isSet("notFollowers")) |
|
this.notFollowers = ns.sessionStorage.get("notFollowers"); |
|
}, |
|
|
|
save: function () { |
|
var ns = $.initNamespaceStorage(this.user); |
|
ns.localStorage.set("followingsFollowings", this.followingsFollowings); |
|
ns.sessionStorage.set("notFollowers", this.notFollowers); |
|
ns.localStorage.set("knownFollowers", this.knownFollowers); |
|
ns.localStorage.set("knownFollowersResetTime", this.knownFollowersResetTime); |
|
}, |
|
|
|
update: function (username) { |
|
var oneshot = false; |
|
var i = 0; |
|
if (typeof(username) !== 'undefined') { |
|
//activate updating for only one user... |
|
i = followingUsers.indexOf(username); |
|
|
|
if (i > -1) { |
|
oneshot = true; |
|
} else { |
|
if (typeof(this.followingsFollowings[username]) !== 'undefined') { |
|
delete this.followingsFollowings[username]; |
|
this.save(); |
|
} |
|
if (typeof _idTrackerMap !== 'undefined' && username in _idTrackerMap) |
|
delete _idTrackerMap[username]; |
|
if (typeof _lastHaveMap !== 'undefined' && username in _lastHaveMap) |
|
delete _lastHaveMap[username]; |
|
return; |
|
} |
|
} |
|
|
|
var updated = false; |
|
for (var user in this.followingsFollowings) { |
|
if (followingUsers.indexOf(user) < 0) { |
|
delete this.followingsFollowings[user]; |
|
updated = true; |
|
} |
|
} |
|
if (updated) |
|
this.save(); |
|
|
|
if (typeof _idTrackerMap !== 'undefined') |
|
for (var user in _idTrackerMap) { |
|
if (followingUsers.indexOf(user) < 0) |
|
delete _idTrackerMap[user]; |
|
} |
|
if (typeof _lastHaveMap !== 'undefined') |
|
for (var user in _lastHaveMap) { |
|
if (followingUsers.indexOf(user) < 0) |
|
delete _lastHaveMap[user]; |
|
} |
|
|
|
for (; i < followingUsers.length; i++) { |
|
var ctime = new Date().getTime() / 1000; |
|
|
|
if (typeof(this.followingsFollowings[followingUsers[i]]) === 'undefined' || |
|
ctime - this.followingsFollowings[followingUsers[i]]["lastUpdate"] >= this.followingsFollowings[followingUsers[i]]["updateInterval"]) { |
|
loadFollowingFromDht(followingUsers[i], 1, [], 0, function (args, following, seqNum) { |
|
if (following.indexOf(args.tf.user) > -1) { |
|
if (args.tf.knownFollowers.indexOf(args.fu) < 0) { |
|
args.tf.knownFollowers.push(args.fu); |
|
} |
|
} else { |
|
if (args.tf.notFollowers.indexOf(args.fu) < 0) { |
|
args.tf.notFollowers.push(args.fu); |
|
} |
|
var tmpi = args.tf.knownFollowers.indexOf(args.fu); |
|
if (tmpi > -1) { |
|
args.tf.knownFollowers.splice(tmpi, 1); |
|
} |
|
} |
|
$(".open-followers").attr("title", args.tf.knownFollowers.length.toString()); |
|
|
|
var ctime = new Date().getTime() / 1000; |
|
if (typeof(args.tf.followingsFollowings[args.fu]) === 'undefined' || |
|
typeof(args.tf.followingsFollowings[args.fu]["following"]) === 'undefined') { |
|
args.tf.followingsFollowings[args.fu] = {}; |
|
args.tf.followingsFollowings[args.fu]["lastUpdate"] = ctime; |
|
args.tf.followingsFollowings[args.fu]["updateInterval"] = TwisterFollowing.minUpdateInterval; |
|
args.tf.followingsFollowings[args.fu]["following"] = following; |
|
} else { |
|
var diff = []; //diff for following |
|
var difu = []; //diff for unfollowing |
|
var ff = args.tf.followingsFollowings[args.fu]["following"]; |
|
|
|
//is there any new following? |
|
for (var j = 0; j < following.length; j++) { |
|
if (ff.indexOf(following[j]) === -1) { |
|
diff.push(following[j]); |
|
ff.push(following[j]); |
|
} |
|
} |
|
//did user unfollow someone? |
|
for (var j = ff.length - 1; j >= 0 && ff.length > following.length; j--) { |
|
if (following.indexOf(ff[j]) === -1) { |
|
difu.push(ff[j]); |
|
ff.splice(j, 1); |
|
} |
|
} |
|
|
|
if (diff.length > 0 || difu.length > 0) { |
|
args.tf.followingsFollowings[args.fu]["updateInterval"] = TwisterFollowing.minUpdateInterval; |
|
args.tf.followingsFollowings[args.fu]["lastUpdate"] = ctime; |
|
} else if (args.tf.followingsFollowings[args.fu]["updateInterval"] < TwisterFollowing.maxUpdateInterval) { |
|
args.tf.followingsFollowings[args.fu]["updateInterval"] *= 2; |
|
} else { |
|
args.tf.followingsFollowings[args.fu]["lastUpdate"] = ctime; |
|
} |
|
} |
|
args.tf.save(); |
|
}, {"tf": this, "fu": followingUsers[i]}); |
|
} |
|
if (oneshot) |
|
break; |
|
} |
|
} |
|
}; |
|
|
|
// load followingUsers from localStorage |
|
function loadFollowingFromStorage() { |
|
var ns=$.initNamespaceStorage(defaultScreenName); |
|
if( ns.localStorage.isSet("followingUsers") ) |
|
followingUsers = ns.localStorage.get("followingUsers"); |
|
if( ns.localStorage.isSet("isFollowPublic") ) |
|
_isFollowPublic = ns.localStorage.get("isFollowPublic"); |
|
if( ns.localStorage.get("followingSeqNum") > _followingSeqNum) |
|
_followingSeqNum = ns.localStorage.get("followingSeqNum"); |
|
if( ns.localStorage.isSet("lastLoadFromDhtTime") ) |
|
_lastLoadFromDhtTime = ns.localStorage.get("lastLoadFromDhtTime"); |
|
// follow ourselves |
|
if(followingUsers.indexOf(defaultScreenName) < 0) { |
|
followingUsers.push(defaultScreenName); |
|
} |
|
} |
|
|
|
// save list of following to localStorage |
|
function saveFollowingToStorage() { |
|
var ns=$.initNamespaceStorage(defaultScreenName); |
|
ns.localStorage.set("followingUsers", followingUsers); |
|
ns.localStorage.set("isFollowPublic", _isFollowPublic); |
|
ns.localStorage.set("followingSeqNum", _followingSeqNum); |
|
ns.localStorage.set("lastLoadFromDhtTime", _lastLoadFromDhtTime); |
|
} |
|
|
|
// load public list of following users from dht resources |
|
// "following1", "following2" etc. |
|
// it will stop loading when resource is empty |
|
// callback is called as: doneCb(doneArg, followingList, seqNum) |
|
function loadFollowingFromDht(username, pageNumber, followingList, seqNum, doneCb, doneArg) { |
|
if( !pageNumber ) pageNumber = 1; |
|
|
|
dhtget( username, "following" + pageNumber, "s", |
|
function(args, following, rawdata) { |
|
if( rawdata ) { |
|
var seq = parseInt(rawdata[0]["p"]["seq"]); |
|
if( seq > args.seqNum ) args.seqNum = seq; |
|
} |
|
|
|
if( following ) { |
|
for( var i = 0; i < following.length; i++ ) { |
|
if( args.followingList.indexOf(following[i]) < 0 ) { |
|
args.followingList.push(following[i]); |
|
} |
|
} |
|
} |
|
|
|
if( following && following.length && args.pageNumber < _maxFollowingPages) { |
|
loadFollowingFromDht(username, args.pageNumber, |
|
args.followingList, args.seqNum, |
|
args.doneCb, args.doneArg); |
|
} else { |
|
if( args.doneCb ) |
|
args.doneCb(args.doneArg, args.followingList, args.seqNum); |
|
} |
|
}, {pageNumber:pageNumber+1, followingList:followingList, seqNum:seqNum, |
|
doneCb:doneCb, doneArg:doneArg}); |
|
} |
|
|
|
// get number of following from dht and set item.text() |
|
function getNumFollowing( username, item ) { |
|
loadFollowingFromDht( username, 1, [], 0, |
|
function(args, following, seqNum) { |
|
item.text( following.length ); |
|
}, null); |
|
} |
|
|
|
function loadFollowingIntoList( username, html_list ) { |
|
loadFollowingFromDht( username, 1, [], 0, |
|
function(args, following, seqNum) { |
|
html_list.html(""); |
|
$.each(following, function(i, following_user){ |
|
var following_user_li = $( "#following-by-user-template" ).children().clone(true); |
|
|
|
// link follower to profile page |
|
$(following_user_li.children()[0]).attr("data-screen-name", following_user); |
|
$(following_user_li.children()[0]).attr("href", $.MAL.userUrl(following_user)); |
|
|
|
following_user_li.find(".following-screen-name b").text(following_user); |
|
getAvatar( following_user, following_user_li.find(".mini-profile-photo") ); |
|
var $followingName = following_user_li.find(".mini-following-name"); |
|
$followingName.text(following_user); |
|
getFullname( following_user, $followingName ); |
|
|
|
html_list.append( following_user_li ); |
|
}); |
|
}, null); |
|
} |
|
|
|
// load following list from localStorage and then from the dht resource |
|
function loadFollowing(cbFunc, cbArg) { |
|
loadFollowingFromStorage(); |
|
updateFollowing(); |
|
|
|
var curTime = new Date().getTime() / 1000; |
|
|
|
// optimization to avoid costly dht lookup everytime the home is loaded |
|
if( curTime > _lastLoadFromDhtTime + 3600*24 || |
|
document.URL.indexOf("following") >= 0 ) { |
|
var numFollow = followingUsers.length; |
|
loadFollowingFromDht( defaultScreenName, 1, [], _followingSeqNum, |
|
function(args, following, seqNum) { |
|
var curTime = new Date().getTime() / 1000; |
|
_lastLoadFromDhtTime = curTime; |
|
|
|
for( var i = 0; i < following.length; i++ ) { |
|
if( followingUsers.indexOf(following[i]) < 0 ) { |
|
followingUsers.push(following[i]); |
|
} |
|
_isFollowPublic[following[i]] = true; |
|
} |
|
|
|
if( args.numFollow != followingUsers.length || |
|
seqNum != _followingSeqNum ) { |
|
_followingSeqNum = seqNum; |
|
// new following loaded from dht |
|
saveFollowingToStorage(); |
|
updateFollowing(); |
|
} |
|
|
|
if( args.cbFunc ) |
|
args.cbFunc(args.cbArg); |
|
}, {numFollow:numFollow, cbFunc:cbFunc, cbArg:cbArg} ); |
|
} else { |
|
if( cbFunc ) |
|
cbFunc(cbArg); |
|
} |
|
} |
|
|
|
// save list of following to dht resource. each page ("following1", following2"...) |
|
// constains up to _followsPerPage elements. alternatively we might keep track |
|
// of total strings size to optimize the maximum storage (8kb in node.cpp, but 4kb is |
|
// probably a good target). |
|
function saveFollowingToDht() { |
|
var following = []; |
|
var pageNumber = 1; |
|
for( var i = 0; i < followingUsers.length; i++ ) { |
|
if( followingUsers[i] in _isFollowPublic && |
|
_isFollowPublic[followingUsers[i]] ) { |
|
following.push(followingUsers[i]); |
|
} |
|
if( following.length == _followsPerPage || i == followingUsers.length-1) { |
|
dhtput( defaultScreenName, "following" + pageNumber, "s", |
|
following, defaultScreenName, _followingSeqNum+1 ); |
|
pageNumber++; |
|
following = []; |
|
} |
|
} |
|
dhtput( defaultScreenName, "following" + pageNumber, "s", |
|
following, defaultScreenName, _followingSeqNum+1 ); |
|
|
|
_followingSeqNum++; |
|
} |
|
|
|
// save following to local storage, dht and json rpc |
|
function saveFollowing(cbFunc, cbArg) { |
|
saveFollowingToDht(); |
|
saveFollowingToStorage(); |
|
updateFollowing(cbFunc, cbArg); |
|
} |
|
|
|
// update json rpc with current list of following |
|
function updateFollowing(cbFunc, cbArg) { |
|
twisterRpc("follow", [defaultScreenName,followingUsers], |
|
function(args, ret) { |
|
if( args.cbFunc ) |
|
args.cbFunc(args.cbArg, true); |
|
}, {cbFunc:cbFunc, cbArg:cbArg}, |
|
function(args, ret) { |
|
console.log("ajax error:" + ret); |
|
if( args.cbFunc ) |
|
args.cbFunc(args.cbArg, false); |
|
}, cbArg); |
|
} |
|
|
|
// follow a new single user. |
|
// it is safe to call this even if username is already in followingUsers. |
|
// may also be used to set/clear publicFollow. |
|
function follow(user, publicFollow, cbFunc, cbArg) { |
|
//console.log('we are following @'+user); |
|
if( followingUsers.indexOf(user) < 0 ) { |
|
followingUsers.push(user); |
|
twisterFollowingO.update(user); |
|
$(window).trigger("eventFollow", user) |
|
} |
|
if( publicFollow == undefined || publicFollow ) |
|
_isFollowPublic[user] = true; |
|
else |
|
delete _isFollowPublic[user]; |
|
saveFollowing(cbFunc, cbArg); |
|
} |
|
|
|
// unfollow a single user |
|
function unfollow(user, cbFunc, cbArg) { |
|
//console.log('we are not following @'+user+' anymore'); |
|
var i = followingUsers.indexOf(user); |
|
if (i >= 0) { |
|
followingUsers.splice(i, 1); |
|
twisterFollowingO.update(user); |
|
// FIXME also need to check list of pending posts to remove from there |
|
$(window).trigger('eventUnfollow', user); |
|
} |
|
delete _isFollowPublic[user]; |
|
saveFollowing(); |
|
|
|
twisterRpc("unfollow", [defaultScreenName,[user]], |
|
function(args, ret) { |
|
if( args.cbFunc ) |
|
args.cbFunc(args.cbArg, true); |
|
}, {cbFunc:cbFunc, cbArg:cbArg}, |
|
function(args, ret) { |
|
console.log("ajax error:" + ret); |
|
if( args.cbFunc ) |
|
args.cbFunc(args.cbArg, false); |
|
}, {cbFunc:cbFunc, cbArg:cbArg}); |
|
} |
|
|
|
// check if public following |
|
function isPublicFollowing(user) { |
|
if( followingUsers.indexOf(user) < 0 ) { |
|
return false; |
|
} |
|
if( (user in _isFollowPublic) && _isFollowPublic[user] == true ) { |
|
//console.log("isPublicFollowing( " +user +" ) = "+true); |
|
return true; |
|
} else { |
|
//console.log("isPublicFollowing( " +user +" ) = "+false); |
|
return false; |
|
} |
|
} |
|
|
|
// check if following list is empty |
|
function followingEmptyOrMyself() { |
|
return (!followingUsers.length || (followingUsers.length === 1 && followingUsers[0] === defaultScreenName)) |
|
} |
|
|
|
// 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. |
|
function getRandomFollowSuggestion() { |
|
if (followingEmptyOrMyself()) |
|
return; |
|
|
|
var i = Math.floor(Math.random() * followingUsers.length); // Math.floor(Math.random() * (max - min + 1)) + min for getting inclusive random from min to max; our min and max are 0 and followingUsers.length - 1 |
|
while (followingUsers[i] === defaultScreenName) |
|
i = Math.floor(Math.random() * followingUsers.length); |
|
|
|
if (typeof twisterFollowingO === 'undefined' || |
|
typeof twisterFollowingO.followingsFollowings[followingUsers[i]] === 'undefined') { |
|
setTimeout(getRandomFollowSuggestion, 500); |
|
return; |
|
} |
|
|
|
var suggested = false; |
|
var j = Math.floor(Math.random() * twisterFollowingO.followingsFollowings[followingUsers[i]].following.length); |
|
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]); |
|
_followSuggestions.push(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]); |
|
suggested = true; |
|
break; |
|
} |
|
} |
|
if (!suggested) |
|
setTimeout(getRandomFollowSuggestion, 500); |
|
} |
|
|
|
function whoFollows(username) { |
|
var list = []; |
|
|
|
for (var following in twisterFollowingO.followingsFollowings) { |
|
if (twisterFollowingO.followingsFollowings[following]["following"].indexOf(username) > -1) { |
|
list.push(following); |
|
} |
|
} |
|
return list; |
|
} |
|
|
|
function fillWhoFollows(list, item, offset, size) { |
|
for (var i = offset; i < offset + size; i++) { |
|
var follower_link = $( '<a class="mini-follower-link"></a>' ); |
|
|
|
// link follower to profile page |
|
follower_link.attr("data-screen-name", list[i]); |
|
follower_link.attr("href", $.MAL.userUrl(list[i])); |
|
follower_link.text(list[i]); |
|
getFullname( list[i], follower_link ); |
|
|
|
item.append( follower_link ); |
|
} |
|
} |
|
|
|
function getWhoFollows(username, item) { |
|
if (!defaultScreenName || typeof(defaultScreenName) === 'undefined') |
|
return; |
|
|
|
var list = whoFollows(username); |
|
|
|
fillWhoFollows(list, item, 0, (list.length > 5 ? 5 : list.length)); |
|
|
|
if (list.length > 5) { |
|
var more_link = $('<a class="show-more-followers">' + polyglot.t('show_more_count', {'smart_count': list.length - 5}) + '</a>'); |
|
more_link.on('click', function() { |
|
fillWhoFollows(list, item, 5, list.length - 5); |
|
|
|
var $this = $(this); |
|
$this.remove(); |
|
|
|
$this.text(polyglot.t('hide')); |
|
$this.unbind('click'); |
|
$this.bind('click', function() { |
|
item.html(''); |
|
getWhoFollows(username, item); |
|
}); |
|
|
|
item.append($this); |
|
}); |
|
item.append(more_link); |
|
} |
|
} |
|
|
|
// adds following users to the interface (following.html) |
|
function showFollowingUsers(){ |
|
var $notFollowing = $(".not-following-any"); |
|
if( followingEmptyOrMyself() ) { |
|
$notFollowing.show(); |
|
} else { |
|
$notFollowing.hide(); |
|
} |
|
|
|
var $followingList = $(".following-list"); |
|
var $template = $("#following-user-template").detach(); |
|
|
|
$followingList.empty(); |
|
$followingList.append($template); |
|
|
|
for( var i = 0; i < followingUsers.length; i++ ) { |
|
var resItem = $template.clone(true); |
|
resItem.removeAttr('id'); |
|
resItem.show(); |
|
resItem.find(".mini-profile-info").attr("data-screen-name", followingUsers[i]); |
|
resItem.find(".following-screen-name").text(followingUsers[i]); |
|
resItem.find("a.open-profile-modal").attr("href",$.MAL.userUrl(followingUsers[i])); |
|
resItem.find("a.direct-messages-with-user").attr("href", $.MAL.dmchatUrl(followingUsers[i])); |
|
if (isPublicFollowing(followingUsers[i])) { |
|
resItem.find(".public-following").text(polyglot.t("Public")); |
|
} else { |
|
resItem.find(".public-following").text(polyglot.t("Private")).addClass( "private" ); |
|
} |
|
getAvatar(followingUsers[i],resItem.find(".mini-profile-photo")); |
|
getFullname(followingUsers[i],resItem.find(".mini-profile-name")); |
|
if( followingUsers[i] == defaultScreenName ) { |
|
resItem.find("button").hide(); |
|
} |
|
|
|
resItem.prependTo($followingList); |
|
toggleFollowButton(followingUsers[i], true) |
|
} |
|
$.MAL.followingListLoaded(); |
|
} |
|
|
|
function processWhoToFollowSuggestion(suggestion, followedBy) { |
|
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)); |
|
|
|
item.find('.twister-user-remove').on('click', function() { |
|
item.remove(); |
|
getRandomFollowSuggestion(); |
|
}); |
|
|
|
list.append(item).show(); |
|
module.find('.refresh-users').show(); |
|
module.find('.loading-roller').hide(); |
|
} else |
|
console.warn('nothing to proceed: no twisters to follow was suggested'); |
|
} |
|
|
|
function closeSearchDialog() |
|
{ |
|
$(".userMenu-search-field").siblings().slideUp( "fast" ); |
|
removeUsersFromDhtgetQueue( _lastSearchUsersResults ); |
|
_lastSearchUsersResults = []; |
|
} |
|
|
|
function userSearchKeypress(event) { |
|
var partialName = $(".userMenu-search-field").val().toLowerCase(); |
|
var searchResults = $(".search-results"); |
|
|
|
if ( partialName.substr( 0, 1 ) == '#' ) { |
|
|
|
if(searchResults.is(":visible")) |
|
searchResults.slideUp( "fast" ); |
|
|
|
if ( event.which == 13 ) |
|
window.location.hash = '#hashtag?hashtag=' + encodeURIComponent(partialName.substr(1)); |
|
|
|
return; |
|
} |
|
|
|
if ( partialName.substr( 0, 1 ) == '@' ) { |
|
partialName = partialName.substr( 1 ); |
|
} |
|
|
|
//var partialName = item.val(); |
|
|
|
if( !partialName.length ) { |
|
closeSearchDialog(); |
|
} else { |
|
if( _searchKeypressTimer !== undefined ) |
|
clearTimeout(_searchKeypressTimer); |
|
|
|
if( _searchingPartialUsers.length ) { |
|
_searchingPartialUsers = partialName; |
|
} else { |
|
_searchKeypressTimer = setTimeout( function() { |
|
_searchKeypressTimer = undefined; |
|
searchPartialUsername(partialName); |
|
}, 600); |
|
} |
|
} |
|
} |
|
|
|
function searchPartialUsername(partialName) { |
|
_searchingPartialUsers = partialName; |
|
twisterRpc("listusernamespartial", [partialName,10], |
|
function(partialName, ret) { |
|
processDropdownUserResults(partialName, ret) |
|
}, partialName, |
|
function(cbArg, ret) { |
|
console.log("ajax error:" + ret); |
|
}, {}); |
|
} |
|
|
|
function processDropdownUserResults(partialName, results){ |
|
|
|
if( partialName != _searchingPartialUsers ) { |
|
searchPartialUsername( _searchingPartialUsers ); |
|
return; |
|
} |
|
|
|
removeUsersFromDhtgetQueue( _lastSearchUsersResults ); |
|
_lastSearchUsersResults = results; |
|
|
|
var typeaheadAccounts = $(".userMenu-search-profiles"); |
|
var template = $("#search-profile-template").detach(); |
|
|
|
typeaheadAccounts.empty(); |
|
typeaheadAccounts.append(template); |
|
|
|
if( results.length ) { |
|
for( var i = 0; i < results.length; i++ ) { |
|
if( results[i] == defaultScreenName ) |
|
continue; |
|
|
|
var resItem = template.clone(true); |
|
resItem.removeAttr('id'); |
|
resItem.show(); |
|
resItem.find(".mini-profile-info").attr("data-screen-name", results[i]); |
|
resItem.find(".mini-screen-name b").text(results[i]); |
|
resItem.find("a.open-profile-modal").attr("href",$.MAL.userUrl(results[i])); |
|
getAvatar(results[i],resItem.find(".mini-profile-photo")); |
|
getFullname(results[i],resItem.find(".mini-profile-name")); |
|
resItem.appendTo(typeaheadAccounts); |
|
if (followingUsers.indexOf(results[i]) >= 0) |
|
toggleFollowButton(results[i], true); |
|
} |
|
|
|
$.MAL.searchUserListLoaded(); |
|
} else { |
|
closeSearchDialog(); |
|
} |
|
_searchingPartialUsers = ""; |
|
} |
|
|
|
function userClickFollow(e) { |
|
e.stopPropagation(); |
|
e.preventDefault(); |
|
|
|
if (!defaultScreenName) { |
|
alert(polyglot.t('You have to log in to follow users.')); |
|
return; |
|
} |
|
|
|
var username = $(e.target).closest('[data-screen-name]').attr('data-screen-name'); |
|
var content = $('#following-config-modal-template').children().clone(true); |
|
|
|
content.closest('.following-config-modal-content').attr('data-screen-name', username); |
|
content.find('.following-config-method-message').text(polyglot.t('Which way do you want to follow')); |
|
content.find('.following-screen-name b').text(username); |
|
|
|
openModal({ |
|
classBase: '.prompt-wrapper', |
|
classAdd: 'following-config-modal', |
|
content: content, |
|
title: polyglot.t('Following config') |
|
}); |
|
} |
|
|
|
function initUserSearch() { |
|
var $userSearchField = $( ".userMenu-search-field" ); |
|
$userSearchField.keyup( userSearchKeypress ); |
|
$userSearchField.bind( "click", userSearchKeypress ); |
|
$(".userMenu-search").clickoutside( closeSearchDialog ); |
|
|
|
// following stuff should be moved to special function |
|
$('button.follow').on('click', userClickFollow); |
|
$('.following-config-method-buttons .public-following') |
|
.on('click', function(e) { |
|
setFollowingMethod(e); |
|
closeModalHandler('.prompt-wrapper'); |
|
window.setTimeout(loadModalFromHash, 500); // delay reload so dhtput may do it's job |
|
}) |
|
; |
|
} |
|
|
|
function followingListPublicCheckbox(e) { |
|
e.stopPropagation(); |
|
|
|
var $this = $(this); |
|
var username = $this.closest(".mini-profile-info").attr("data-screen-name"); |
|
var publicFollow = false; |
|
$this.toggleClass( "private" ); |
|
if( $this.hasClass( "private" ) ) { |
|
$this.text( polyglot.t("Private") ); |
|
} else { |
|
$this.text( polyglot.t("Public") ); |
|
publicFollow = true; |
|
} |
|
|
|
//console.log("set following method of @" +username +" for "+publicFollow); |
|
follow(username, publicFollow); |
|
} |
|
|
|
function setFollowingMethod(event) { |
|
var button = $(event.target); |
|
var username = button.closest('.following-config-modal-content').attr('data-screen-name'); |
|
|
|
follow(username, |
|
(button.hasClass('private')) ? false : true, // is folowing public |
|
toggleFollowButton, username, true // last two are args for toggleFollowButton() |
|
); |
|
|
|
event.stopPropagation(); |
|
} |
|
|
|
|
|
function requestSwarmProgress() { |
|
twisterRpc("getlasthave", [defaultScreenName], |
|
function(args, ret) {processSwarmProgressPartial(ret);}, null, |
|
function(args, ret) {console.log("ajax error:" + ret);}, null); |
|
} |
|
|
|
function processSwarmProgressPartial(lastHaves) |
|
{ |
|
if( defaultScreenName in lastHaves ) { |
|
incLastPostId(lastHaves[defaultScreenName]); |
|
} |
|
|
|
twisterRpc("getnumpieces", [defaultScreenName], |
|
function(args, ret) {processSwarmProgressFinal(args.lastHaves, ret);}, |
|
{lastHaves:lastHaves}, |
|
function(args, ret) {console.log("ajax error:" + ret);}, null); |
|
} |
|
|
|
function processSwarmProgressFinal(lastHaves, numPieces) |
|
{ |
|
for( var user in lastHaves ) { |
|
if( lastHaves.hasOwnProperty(user) && numPieces.hasOwnProperty(user) ) { |
|
var $userDiv = $(".mini-profile-info[data-screen-name='" + user + "']"); |
|
if( $userDiv.length ) { |
|
var $status = $userDiv.find(".swarm-status"); |
|
$status.text(polyglot.t("download_posts_status", { portion: numPieces[user] + "/" + (lastHaves[user]+1) })); |
|
$status.fadeIn(); |
|
} |
|
} |
|
} |
|
window.setTimeout(requestSwarmProgress, 2000); |
|
} |
|
|
|
function followingChangedUser() { |
|
followingUsers = []; |
|
_isFollowPublic = {}; |
|
_followingSeqNum = 0; |
|
_followSuggestions = []; |
|
_lastLoadFromDhtTime = 0; |
|
} |
|
|
|
function initInterfaceFollowing() { |
|
initInterfaceCommon(); |
|
initUserSearch(); |
|
initInterfaceDirectMsg(); |
|
|
|
$(".mini-profile-info .public-following").bind( "click", followingListPublicCheckbox ); |
|
|
|
$(".mentions-from-user").bind( "click", openMentionsModal ); |
|
|
|
initUser( function() { |
|
if( !defaultScreenName ) { |
|
alert(polyglot.t("username_undefined")); |
|
$.MAL.goLogin(); |
|
return; |
|
} |
|
checkNetworkStatusAndAskRedirect(); |
|
|
|
$(".postboard-loading").fadeIn(); |
|
loadFollowing( function(args) { |
|
twisterFollowingO = TwisterFollowing(defaultScreenName); |
|
|
|
showFollowingUsers(); |
|
requestSwarmProgress(); |
|
}); |
|
initMentionsCount(); |
|
initDMsCount(); |
|
}); |
|
|
|
$(window) |
|
.on('eventFollow', function(e, user) { |
|
$('.mini-profile .following-count').text(followingUsers.length - 1); |
|
showFollowingUsers(); |
|
}) |
|
.on('eventUnfollow', function(e, user) { |
|
$('.mini-profile .following-count').text(followingUsers.length - 1); |
|
showFollowingUsers(); |
|
}); |
|
} |
|
|
|
|
|
var InterfaceFunctions = function() |
|
{ |
|
this.init = function() |
|
{ |
|
initUser(initFollowing_); |
|
initHashWatching(); |
|
}; |
|
|
|
function initFollowing_(cbFunc, cbArg) { |
|
var $miniProfile = $(".left .mini-profile"); |
|
if(!defaultScreenName) |
|
{ |
|
|
|
} |
|
else |
|
{ |
|
$miniProfile.find("a.mini-profile-name").attr("href",$.MAL.userUrl(defaultScreenName)); |
|
$miniProfile.find("a.open-profile-modal").attr("href",$.MAL.userUrl(defaultScreenName)); |
|
$miniProfile.find(".mini-profile-name").text(defaultScreenName); |
|
getFullname( defaultScreenName, $miniProfile.find(".mini-profile-name") ); |
|
getAvatar( defaultScreenName, $miniProfile.find(".mini-profile-photo").find("img") ); |
|
getPostsCount( defaultScreenName, $miniProfile.find(".posts-count") ); |
|
getFollowers( defaultScreenName, $miniProfile.find(".followers-count") ); |
|
|
|
loadFollowing( function(args) { |
|
$(".left .following-count").text(followingUsers.length-1); |
|
initMentionsCount(); |
|
initDMsCount(); |
|
}, {cbFunc:cbFunc, cbArg:cbArg}); |
|
|
|
} |
|
|
|
} |
|
}; |
|
|
|
//*********************************************** |
|
//******************* INIT ************** |
|
//*********************************************** |
|
if (!/\/home.html$/i.test(document.location)) { // FIXME we're doing it wrong, interfaceFunctions declaration should be inside interface common |
|
var interfaceFunctions = new InterfaceFunctions; |
|
$(document).ready(interfaceFunctions.init); |
|
}
|
|
|