// twister_actions.js // 2013 Miguel Freitas // // This file contains some twister "actions" like requesting // posts from dht, sending posts, replies. It seems to be a // intermediate layer between twister_io and interface, but // separation is not clearly defined. Perhaps it would be better // to get rid of this file altogether. // global variables var postsPerRefresh = 10; var maxExpandPost = 8; var maxExpandPostTop = 4; var _hashtagProcessedMap = {}; var _hashtagPendingPosts = []; var _hashtagPendingPostsUpdated = 0; var autoUpdateHashtag = false; // ---------------- function requestRepliedBefore(postLi) { if(postLi.siblings().length >= maxExpandPostTop) return; var originalPost = postLi.find(".post-data"); var reply_n = originalPost.attr('data-replied-to-screen-name'); var reply_k = originalPost.attr('data-replied-to-id'); if( reply_n != undefined && reply_k != undefined ) { dhtget( reply_n, "post" + reply_k, "s", function(postLi, postFromJson) { var newStreamPost = postToElem(postFromJson, "related"); newStreamPost.hide(); postLi.before(newStreamPost); newStreamPost.slideDown("fast"); $.MAL.relatedPostLoaded(); requestRepliedBefore(newStreamPost); }, postLi); } } function requestRepliesAfter(postLi) { if($.MAL.getExpandedPostsCount(postLi) >= maxExpandPost) return; var originalPost = postLi.find(".post-data"); var original_n = originalPost.attr('data-screen-name'); var original_k = originalPost.attr('data-id'); if( original_n != undefined && original_k != undefined ) { dhtget( original_n, "replies" + original_k, "m", $.MAL.reqRepAfterCB, postLi); } } function getTopPostOfConversation(postLi, post, postboard) { var reply_n; var reply_k; if (post && typeof(post) !== 'undefined' && "reply" in post["userpost"]) { reply_k = post["userpost"]["reply"]["k"]; reply_n = post["userpost"]["reply"]["n"]; } else if (postLi && typeof(postLi) !== 'undefined') { var originalPost = postLi.find(".post-data"); reply_n = originalPost.attr('data-replied-to-screen-name'); reply_k = originalPost.attr('data-replied-to-id'); } if( reply_n != undefined && reply_k != undefined ) { dhtget( reply_n, "post" + reply_k, "s", function(postLi, postFromJson) { getTopPostOfConversation(null, postFromJson, postboard); }, postLi); } else { var newStreamPost; if (post) newStreamPost = postToElem(post, "related"); else { newStreamPost = postLi.clone(true); newStreamPost.removeClass('original'); newStreamPost.addClass('related'); newStreamPost.find('.expanded-content').hide(); newStreamPost.find('.show-more').hide(); } requestRepliesAfterAll(newStreamPost); newStreamPost.find('.post-expand').remove(); newStreamPost.unbind('click'); newStreamPost.hide(); postboard.append(newStreamPost); newStreamPost.slideDown("fast"); } } function requestRepliesAfterAll(postLi) { var originalPost = postLi.find(".post-data"); var original_n = originalPost.attr('data-screen-name'); var original_k = originalPost.attr('data-id'); if( original_n != undefined && original_k != undefined ) { dhtget( original_n, "replies" + original_k, "m", $.MAL.reqRepAfterCB, postLi); } } function requestRTs(postLi) { var originalPost = postLi.find(".post-data"); var original_n = originalPost.attr('data-screen-name'); var original_k = originalPost.attr('data-id'); if( original_n != undefined && original_k != undefined ) { dhtget( original_n, "rts" + original_k, "m", function(originalPost, postsFromJson) { if( postsFromJson.length ) { var statCountValue = originalPost.find(".stat-count-value"); statCountValue.text( postsFromJson.length ); var avatarRow = originalPost.find(".avatar-row"); avatarRow.empty(); for( var i = 0; i < postsFromJson.length && i < 8; i++) { var n = postsFromJson[i]["userpost"]["n"]; var elemUser = $("#avatar-row-template").clone(true); elemUser.removeAttr('id'); elemUser.attr('href',$.MAL.userUrl(n)); getFullname(n,elemUser.find(".user-name-tooltip")); getAvatar(n,elemUser.find(".size24")); avatarRow.append( elemUser ); } originalPost.find(".post-stats").slideDown("fast"); } }, originalPost); } } function appendPostToContainer(postFromJson, containerToAppend) { var newStreamPost = postToElem(postFromJson, "original"); newStreamPost.hide(); containerToAppend.append( newStreamPost ); newStreamPost.slideDown("fast"); $.MAL.postboardLoaded(); } var profilePostsLoading = false; function requestPost(containerToAppend,username,resource,cbFunc,cbArgs){ console.log('dhtget '+username+' '+resource); dhtget( username, resource, "s", function(args, postFromJson) { if( postFromJson ) { console.log(postFromJson); appendPostToContainer(postFromJson,args.containerToAppend); if(args.cbFunc!=undefined) args.cbFunc(args.cbArgs); } }, {containerToAppend:containerToAppend,cbFunc:cbFunc,cbArgs:cbArgs} ); } function requestPostRecursively(containerToAppend,username,resource,count,useGetposts) { var max_id = -1; if( !resource ) { var streamItems = containerToAppend.children(); if( streamItems.length != 0 ) { var lastItem = streamItems.eq(streamItems.length-1); resource = "post" + lastItem.find(".post-data").attr("data-lastk"); max_id = parseInt(lastItem.find(".post-data").attr("data-lastk")); } } profilePostsLoading = true; if( useGetposts ) { req = {username: username} if( max_id != -1 ) { req.max_id = max_id; } twisterRpc("getposts", [count,[req]], function(args, posts) { for( var i = 0; i < posts.length; i++ ) { appendPostToContainer(posts[i],args.containerToAppend); } profilePostsLoading = false; }, {containerToAppend:containerToAppend}, function(args, ret) { profilePostsLoading = false; }, {}); } else { dhtget( username, resource, "s", function(args, postFromJson) { if( postFromJson ) { appendPostToContainer(postFromJson,args.containerToAppend); if( args.count > 1 ) { var userpost = postFromJson["userpost"]; var n = userpost["n"]; var lastk = userpost["lastk"]; if( lastk == undefined ) lastk = userpost["k"] - 1; // not true with directmsgs in stream requestPostRecursively(args.containerToAppend, n, "post"+lastk, count-1); } else { profilePostsLoading = false; args.containerToAppend.scroll(); } } else { profilePostsLoading = false; } }, {containerToAppend:containerToAppend, count:count} ); } } function newPostMsg(msg, $postOrig) { if( lastPostId != undefined ) { if ( typeof _sendedPostIDs !== 'undefined' ) _sendedPostIDs.push(lastPostId + 1); var params = [defaultScreenName, lastPostId + 1, msg] if( $postOrig.length ) { params.push($postOrig.attr('data-screen-name')); params.push(parseInt($postOrig.attr('data-id'))); } twisterRpc("newpostmsg", params, function(arg, ret) { incLastPostId(); }, null, function(arg, ret) { var msg = ("message" in ret) ? ret.message : ret; alert(polyglot.t("ajax_error", { error: msg })); }, null); } else { alert(polyglot.t("Internal error: lastPostId unknown (following yourself may fix!)")); } } function newRtMsg($postOrig) { var content_to_rt = $postOrig.attr('data-content_to_rt'); var content_to_sigrt = $postOrig.attr('data-content_to_sigrt'); var sig_userpost = String(content_to_sigrt); var userpost = $.evalJSON(String(content_to_rt)); var rtObj = { sig_userpost :sig_userpost, userpost : userpost }; if( lastPostId != undefined ) { if ( typeof _sendedPostIDs !== 'undefined' ) _sendedPostIDs.push(lastPostId + 1); var params = [defaultScreenName, lastPostId+1, rtObj] twisterRpc("newrtmsg", params, function(arg, ret) { incLastPostId(); }, null, function(arg, ret) { var msg = ("message" in ret) ? ret.message : ret; alert(polyglot.t("ajax_error", { error: msg })); }, null); } else { alert(polyglot.t("Internal error: lastPostId unknown (following yourself may fix!)")); } } function updateProfileData(profileModalContent, username) { //profileModalContent.find("a").attr("href",$.MAL.userUrl(username)); profileModalContent.filter(".profile-card").attr("data-screen-name", username); profileModalContent.find(".profile-screen-name b").text(username); profileModalContent.find("a.follow").attr("href", $.MAL.followUrl(username)); profileModalContent.find("a.direct-messages-with-user").attr("href", $.MAL.dmchatUrl(username)); profileModalContent.find("a.new-post-to").attr("href", $.MAL.newPostToUrl(username)); profileModalContent.find("a.mentions-from-user").attr("href", $.MAL.mentionsUrl(username)); getFullname( username, profileModalContent.find(".profile-name") ); getLocation( username, profileModalContent.find(".profile-location") ); getWebpage( username, profileModalContent.find(".profile-url") ); getBio( username, profileModalContent.find(".profile-bio") ); getTox( username, profileModalContent.find(".profile-tox") ); getBitmessage( username, profileModalContent.find(".profile-bitmessage") ); getAvatar( username, profileModalContent.find(".profile-card-photo") ); getPostsCount( username, profileModalContent.find(".posts-count") ); getFollowers( username, profileModalContent.find(".followers-count") ); getNumFollowing( username, profileModalContent.find(".following-count") ); getWhoFollows ( username, profileModalContent.find(".who-follow") ); profileModalContent.find(".following-count").parent().attr("href", $.MAL.followingUrl(username)); var postsView = profileModalContent.find(".postboard-posts"); // try using getposts first. fallback to dht. twisterRpc("getposts", [1,[{username: username}]], function(args, posts) { updateProfilePosts(postsView, username, posts.length); }, {}, function(args, ret) { updateProfilePosts(postsView, username, false); }, {}); } function updateProfilePosts(postsView, username, useGetposts) { requestPostRecursively(postsView,username,"status",postsPerRefresh, useGetposts); postsView.scroll(function(){ if (!profilePostsLoading) { var $this = $(this); if ($this.scrollTop() >= this.scrollHeight - $this.height() - 20) { requestPostRecursively($this,username,"",postsPerRefresh, useGetposts); } } }); } function updateFollowingData(followingModalContent, username) { followingModalContent.find(".following-screen-name b").text(username); loadFollowingIntoList( username, $(followingModalContent[1]) ); } function clearHashtagProcessed() { _hashtagProcessedMap = {}; _hashtagPendingPosts = []; } function requestHashtag(postboard,hashtag,resource, timeoutArgs) { dhtget( hashtag, resource, "m", function(args, data) { processHashtag(args.postboard, args.hashtag, data); }, {postboard:postboard,hashtag:hashtag}, timeoutArgs); } function processHashtag(postboard, hashtag, data) { if( data && window.location.hash.indexOf(encodeURIComponent(hashtag)) != -1 ) { for( var i = data.length-1; i >= 0; i-- ) { var userpost = data[i]["userpost"]; var key = userpost["n"] + ";" + userpost["time"]; if( !(key in _hashtagProcessedMap) ) { _hashtagProcessedMap[key] = true; _hashtagPendingPosts.push(data[i]); _hashtagPendingPostsUpdated++; } } if(!postboard.children().length && !_hashtagPendingPosts.length && hashtag != defaultScreenName) postboard.closest("div").find(".no-posts-found-message").show(); if( _hashtagPendingPosts.length ) { if( !postboard.children().length || autoUpdateHashtag ) { displayHashtagPending(postboard); } else { var newTweetsBar = postboard.closest("div").find(".postboard-news"); newTweetsBar.text(polyglot.t("new_posts", _hashtagPendingPosts.length)); newTweetsBar.fadeIn("slow"); } postboard.closest("div").find(".no-posts-found-message").hide(); } } } function displayHashtagPending(postboard) { for( var i = 0; i < _hashtagPendingPosts.length; i++ ) { var streamPost = postToElem(_hashtagPendingPosts[i], "original"); var timePost = _hashtagPendingPosts[i]["userpost"]["time"]; var streamItems = postboard.children(); if( streamItems.length == 0) { postboard.prepend( streamPost ); } else { var j = 0; for( j = 0; j < streamItems.length; j++) { var streamItem = streamItems.eq(j); var timeItem = streamItem.attr("data-time"); if( timeItem == undefined || timePost > parseInt(timeItem) ) { // this post in stream is older, so post must be inserted above streamItem.before(streamPost); break; } } if( j == streamItems.length ) { postboard.append( streamPost ); } } } $.MAL.postboardLoaded(); _hashtagPendingPosts = []; }