twister HTML + Javascript User Interface
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.
 
 
 
 

630 lines
23 KiB

// tmobile.js
// 2013 Miguel Freitas
//
// mobile interface for twister using jquery mobile + router
var twisterInitialized = false;
var handlersInstalled = false;
function initializeTwister( redirectNetwork, redirectLogin, cbFunc, cbArg ) {
if( !handlersInstalled ) {
interfaceNetworkHandlers();
installUserSearchHandler();
installProfileEditHandlers();
// install scrollbottom handler to load more posts as needed
$(window).on('scroll', function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 20){
reachedScrollBottom();
}
});
// home screen timeline refresh button
$('.timeline-refresh').on('click', function (e) {
requestTimelineUpdate("latest",postsPerRefresh,followingUsers);
$.mobile.silentScroll(0);
});
// reply text counter both newmsg and dmchat
$('.post-area-new textarea')
.off('input keyup')
.on('focus', poseTextareaPostTools)
.on('keyup', replyTextInput)
.on('keyup', function() { replyTextUpdateRemaining(this); })
;
handlersInstalled = true;
twister.tmpl.post = extractTemplate('#template-post');
twister.tmpl.postFull = extractTemplate('#template-post-full');
twister.tmpl.postFull.find('.post-stats').hide();
}
if( twisterInitialized ) {
if( cbFunc )
cbFunc(cbArg);
} else {
networkUpdate( function() {
if( redirectNetwork && !twisterdConnectedAndUptodate ) {
$.MAL.goNetwork();
return;
}
initUser(function() {
if( redirectLogin && !defaultScreenName ) {
$.MAL.goLogin();
return;
}
if( defaultScreenName ) {
loadFollowing( function(args) {
requestLastHave();
initMentionsCount();
initDMsCount();
twisterFollowingO = TwisterFollowing(defaultScreenName);
twisterInitialized = true;
if( cbFunc )
cbFunc(cbArg);
setInterval("tmobileTick()", 2000);
});
} else {
if( cbFunc )
cbFunc(cbArg);
}
});
});
}
}
var router=new $.mobile.Router(
[
{ "#index" : {handler: "index", events: "bc"} },
{ "#home": {handler: "home", events: "bs" } },
{ "#profile": {handler: "profile", events: "bs" } },
{ "#profile-edit": {handler: "profileedit", events: "bs" } },
{ "#following": {handler: "following", events: "bs" } },
{ "#post": {handler: "post", events: "bs" } },
{ "#newmsg": {handler: "newmsg", events: "bs" } },
{ "#rt": {handler: "rt", events: "bs" } },
{ "#mentions": {handler: "mentions", events: "bs" } },
{ "#hashtag": {handler: "hashtag", events: "bs" } },
{ "#login": {handler: "login", events: "bs" } },
{ "#network": {handler: "network", events: "bs" } },
{ "#directmsg": {handler: "directmsg", events: "bs" } },
{ "#dmchat": {handler: "dmchat", events: "bs" } },
{ "#search": {handler: "search", events: "bs" } },
{ "#new-user-modal": {handler: "newusermodal", events: "bs" } },
],{
index: function(type,match,ui) {
$.mobile.loading('show');
initializeTwister( true, true, function() {
//$.MAL.goHome();
});
},
home: function(type,match,ui) {
$.mobile.loading('show');
initializeTwister( true, true, function() {
if( !$("#home .posts").children().length ) {
$.mobile.loading('show');
cleanupStorage();
getFullname( defaultScreenName, $("#home .rtitle"));
$(".mentions-count").attr("href","#mentions?user="+defaultScreenName );
requestTimelineUpdate("latestFirstTime",postsPerRefresh,followingUsers);
}
});
},
profile: function(type,match,ui) {
var params=router.getParams(match[1]);
clearProfilePage();
$.mobile.loading('show');
initializeTwister( true, true, function() {
var user;
if( params && params.hasOwnProperty("user") ) {
user = params.user;
} else {
user = defaultScreenName;
}
var $newmsgLink = $("a.profile-newmsg");
if( user != defaultScreenName ) {
$newmsgLink.attr("href",$.MAL.newPostToUrl(user)).show();
} else {
$newmsgLink.hide();
}
$.mobile.loading('show');
updateProfileData( $("#profile"), user);
});
},
profileedit: function(type,match,ui) {
$.mobile.loading('show');
initializeTwister( true, true, function() {
var containerElem = $('.profile-card.forEdition');
loadProfileForEdit(defaultScreenName, {
fullname: containerElem.find('.input-name').attr('placeholder', polyglot.t('Full name here')),
bio: containerElem.find('.input-bio').attr('placeholder', polyglot.t('Describe yourself')),
location: containerElem.find('.input-location').attr('placeholder', polyglot.t('Location')),
url: containerElem.find('.input-url').attr('placeholder', polyglot.t('website'))
});
loadAvatarForEdit(defaultScreenName, $('.profile-card-photo.forEdition'));
dumpPrivkey(defaultScreenName, function(args, key) {
$(".secret-key").text(key);
}, {});
});
},
following: function(type,match,ui) {
var params=router.getParams(match[1]);
clearProfilePage();
$.mobile.loading('show');
initializeTwister( true, true, function() {
var user;
if( params && params.hasOwnProperty("user") ) {
user = params.user;
} else {
user = defaultScreenName;
}
if( params && params.hasOwnProperty("follow") ) {
follow(params.follow);
}
if( params && params.hasOwnProperty("unfollow") ) {
unfollow(params.unfollow);
}
$.mobile.loading('show');
$("#following a.ui-btn").removeClass("ui-btn-active");
var followingList = twister.tmpl.followingList.clone(true).appendTo($("#following .content"))
.closest('.following-list').listview();
appendFollowingToElem(followingList);
followingList.find('[data-role="button"]').button();
});
},
post: function(type,match,ui) {
initializeTwister( true, true, function (req) {
if (!req || !req.userpost) return;
var originalLi = postToElem(JSON.parse(req.userpost), 'original', false, twister.tmpl.postFull)
.addClass('expanded-post')
;
var $ulPost = $("#post ul.posts");
$ulPost.text("");
$ulPost.append(originalLi);
$ulPost.find(".post-interactions").trigger('create');
$ulPost.listview('refresh');
installReplyClick();
installRetransmitClick();
// insert replies to this post after
requestRepliesAfter(originalLi);
// RTs faces and counter
var postDataElem = originalLi.find('.post-data');
requestRTs(postDataElem.attr('data-screen-name'), postDataElem.attr('data-id'));
}, router.getParams(match[1]));
},
newmsg: function(type,match,ui) {
var params=router.getParams(match[1]);
initializeTwister( true, true, function() {
var $replyTextarea = $("#newmsg .post-area-new textarea");
$replyTextarea.attr("placeholder", polyglot.t("New Post..."));
if( params && params.hasOwnProperty("replyto") ) {
$replyTextarea.val(params.replyto);
} else {
$replyTextarea.val("");
}
$.MAL.disableButton($("#newmsg .post-submit"));
var $replyOriginal = $(".reply-original-post")
$replyOriginal.html("");
if( params && params.hasOwnProperty("userpost") ) {
var originalLi = postToElem(JSON.parse(params.userpost), 'original');
$replyOriginal.append(originalLi);
$replyOriginal.listview('refresh');
}
installSubmitClick();
});
},
rt: function(type,match,ui) {
var params=router.getParams(match[1]);
initializeTwister( true, true, function() {
var $rtOriginal = $(".rt-original-post")
$rtOriginal.html("");
var originalLi = postToElem(JSON.parse(params.userpost), 'original');
$rtOriginal.append(originalLi);
$rtOriginal.listview('refresh');
installRetransmitConfirmClick();
});
},
mentions: function(type,match,ui) {
var params=router.getParams(match[1]);
$.mobile.loading('show');
initializeTwister( true, true, function() {
var user;
var $newmsgLink = $("a.mention-newmsg");
if( params && params.hasOwnProperty("user") ) {
user = params.user;
$newmsgLink.attr("href",$.MAL.newPostToUrl(user));
} else {
user = defaultScreenName;
$newmsgLink.attr("href","#newmsg");
resetMentionsCount();
}
$("#mentions .rtitle").text(polyglot.t("mentions_at", { user: user }));
var $ulMentions = $("#mentions ul.posts");
setupHashtagOrMention( $ulMentions, user, "mention");
});
},
hashtag: function(type,match,ui) {
var params=router.getParams(match[1]);
$.mobile.loading('show');
initializeTwister( true, true, function() {
$("#hashtag .rtitle").text("#" + params.hashtag);
$("a.hashtag-newmsg").attr("href",$.MAL.newPostHashtagToUrl(params.hashtag));
var $ulHashtag = $("#hashtag ul.posts");
setupHashtagOrMention($ulHashtag,params.hashtag,"hashtag");
});
},
login: function(type,match,ui) {
if (!$('#login .content').children().length)
$('#login .content').append(twister.tmpl.loginMC.clone(true)).trigger('create');
$.mobile.loading('show');
initializeTwister( true, false, function() {
$.mobile.loading('hide');
$("select.local-usernames").selectmenu("refresh", true);
});
},
network: function(type,match,ui) {
$.mobile.loading('show');
initializeTwister( false, false, function() {
$.mobile.loading('hide');
$("select.local-usernames.spam-user").selectmenu("refresh", true);
getSpamMsg();
getGenerate();
});
},
directmsg: function(type,match,ui) {
$.mobile.loading('show');
initializeTwister( true, true, function() {
$.mobile.loading('show');
modalDMsSummaryDraw($('#directmsg .direct-messages-list'));
});
},
dmchat: function(type,match,ui) {
var params=router.getParams(match[1]);
$.mobile.loading('show');
initializeTwister( true, true, function() {
var peerAlias = params.user;
var board = $('#dmchat .direct-messages-thread').empty();
$('#dmchat .rtitle').text('Chat @' + peerAlias);
$("#dmchat textarea").val("");
installDMSendClick(peerAlias);
$.mobile.loading('show');
tmobileQueryReq = queryStart(board, peerAlias, 'direct', undefined, 2000, {
boardAutoAppend: true,
lastId: 0,
lengthNew: 0,
ready: function (req, peerAlias) {
twister.DMs[peerAlias] = twister.res[req];
},
readyReq: peerAlias,
drawFinish: function (req) {
setTimeout($.MAL.dmConversationLoaded, 200, twister.res[req].board);
},
skidoo: function (req) {
return $.mobile.activePage.attr('id') !== 'dmchat' || req !== tmobileQueryReq;
}
});
});
},
search: function(type,match,ui) {
initializeTwister( true, true, function() {
/**/
});
},
newusermodal: function(type,match,ui) {
initializeTwister( false, false, function() {
/* dumpPrivkey(defaultScreenName, function(args, key) {
$(".secret-key").text(key);
}, {}); */
});
},
}, {
defaultHandler: function(type, ui, page) {
console.log("Default handler called due to unknown route ("
+ type + ", " + ui + ", " + page + ")" );
console.log(ui);
console.log(page);
},
defaultHandlerEvents: "s",
defaultArgsRe: true
}
);
function installPostboardClick() {
var $postDatas = $(".post-data");
$postDatas.off('click').on('click', function (e) {
e.stopPropagation();
e.preventDefault();
var userpost = $(this).attr("data-userpost");
var url = "#post?userpost=" + encodeURIComponent(userpost);
$.mobile.loading('show');
$.mobile.navigate( url );
});
$(".post a").off('click').on('click', function (e) {
e.stopPropagation();
// stopPropagation is supposed to be enough, but in Android the
// default action is not called so we reimplement it here as a hack.
e.preventDefault();
$.mobile.loading('show');
$.mobile.navigate( $(this).attr("href") );
});
}
function installReplyClick() {
var $postReply = $("#post .post-reply");
$postReply.off('click').on('click', function (e) {
e.stopPropagation();
e.preventDefault();
var $postData = $(this).closest(".post-data");
var userpost = $postData.attr("data-userpost");
var replyTo = $postData.attr("data-reply-to");
var url = "#newmsg?replyto=" + encodeURIComponent(replyTo) +
"&userpost=" + encodeURIComponent(userpost);
$.mobile.loading('show');
$.mobile.navigate( url );
});
}
function installRetransmitClick() {
var $postRt = $("#post .post-propagate");
$postRt.off('click').on('click', function (e) {
e.stopPropagation();
e.preventDefault();
var $postData = $(this).closest(".post-data");
var userpost = $postData.attr("data-userpost");
var url = "#rt?userpost=" + encodeURIComponent(userpost);
$.mobile.loading('show');
$.mobile.navigate( url );
});
}
function installSubmitClick() {
var $postSubmit = $(".post-submit");
$postSubmit.off('click').on('click', function (e) {
e.stopPropagation();
e.preventDefault();
var $this = $( this );
var $replyText = $this.closest(".post-area-new").find("textarea");
var $postOrig = $("#newmsg .reply-original-post .post-data");
var s = encode_utf8($replyText.val());
newPostMsg(s, $postOrig.attr('data-screen-name'), parseInt($postOrig.attr('data-id')));
$replyText.val("");
$replyText.attr("placeholder", polyglot.t("Your message was sent!"));
setTimeout( function() {$.MAL.goHome();}, 1000);
});
}
function installDMSendClick(peerAlias) {
$('.dm-submit').off('click').on('click', {peerAlias: peerAlias},
function (event) {
muteEvent(event, true);
var elemTextArea = $(event.target).closest('.post-area-new').find('textarea');
if (!elemTextArea.val())
return;
newDirectMsg(encode_utf8(elemTextArea.val()), event.data.peerAlias);
elemTextArea.val('');
}
);
}
function installRetransmitConfirmClick() {
var $postConfirmRt = $(".retransmit-confirm");
$postConfirmRt.off('click').on('click', function (e) {
e.stopPropagation();
e.preventDefault();
var $postOrig = $("#rt .rt-original-post .post-data");
$.mobile.loading('show');
newRtMsg($postOrig);
$.MAL.goHome();
});
}
function installUserSearchHandler() {
$('.userMenu-search-field')
.off('click input')
.on('keyup', userSearchEnter)
.on('click keyup',
{hashtags: true, handleRet: processDropdownUserResults,
handleRetZero: closeSearchDialog}, userSearchKeypress)
;
}
function installProfileEditHandlers() {
$('.profile-card-photo.forEdition').on('click', function () {$('#avatar-file').trigger('click');});
$('#avatar-file').on('change', handleAvatarFileSelectMobile);
$('.submit-changes').on('click', function (event) {
var saveElem = $(event.target);
var containerElem = saveElem.closest('.content');
$.MAL.disableButton(saveElem);
saveProfile(defaultScreenName,
{
fullname: containerElem.find('.input-name').val(),
bio: containerElem.find('.input-bio').val(),
location: containerElem.find('.input-location').val(),
url: containerElem.find('.input-url').val(),
tox: containerElem.find('.input-tox').val(),
bitmessage: containerElem.find('.input-bitmessage').val()
},
function (req) {
saveAvatar(req.peerAlias, req.avatarData,
function () {
alert(polyglot.t('profile_saved'));
$.MAL.goHome();
},
null,
function (req) {
alert(polyglot.t('profile_not_saved') + '\n\nCan\'t save avatar data.');
$.MAL.enableButton(req);
},
req.saveElem
);
},
{
peerAlias: defaultScreenName,
avatarData: containerElem.find('.profile-card-photo.forEdition').attr('src'),
saveElem: saveElem
},
function (req) {
alert(polyglot.t('profile_not_saved') + '\n\nCan\'t save profile data.');
$.MAL.enableButton(req);
},
saveElem
);
});
$('.cancel-changes').on('click', $.mobile.back);
}
function handleAvatarFileSelectMobile(evt) {
var files = evt.target.files; // FileList object
var f = files[0];
// Only process image files.
if (f.type === undefined || f.type.match('image.*')) {
var reader;
try {
reader = new FileReader();
} catch(e) {
alert(polyglot.t('File APIs not supported in this browser.'));
return;
}
reader.onload=function(e){
var img=new Image();
img.onload=function(){
var MAXWidthHeight=64;
var r=MAXWidthHeight/Math.max(this.width,this.height),
w=Math.round(this.width*r),
h=Math.round(this.height*r),
c=document.createElement("canvas");
c.width=w;c.height=h;
c.getContext("2d").drawImage(this,0,0,w,h);
var imgURL = undefined;
var encoder = new JPEGEncoder();
for(var q = 90; (!imgURL || imgURL.length > 4096) && q > 10; q -= 1) {
imgURL = encoder.encode(c.getContext("2d").getImageData(0,0,w,h), q);
console.log( "q: " + q + " url size: " + imgURL.length );
}
$(".profile-card-photo.forEdition").attr("src", imgURL );
}
img.src=e.target.result;
}
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
function handleClickOpenConversation(event) {
event.stopPropagation();
event.preventDefault();
var userpost = $(event.target).closest(event.data.feeder).attr('data-userpost');
$.mobile.loading('show');
$.mobile.navigate('#post?userpost=' + encodeURIComponent(userpost));
}
function clearProfilePage() {
$("#profile .profile-card-photo").attr("src","img/grayed_avatar_placeholder_24.png");
$("#profile .profile-name").text("");
$("#profile .profile-location").text("");
$("#profile .profile-url").text("");
$("#profile .profile-url").attr("href","");
$("#profile .profile-location").text("");
$("#profile .posts").text("");
}
// handler of scroll bottom to request older posts
function reachedScrollBottom() {
var curPage = $.mobile.activePage.attr("id");
if( curPage == "home" ) {
if( timelineLoaded ) {
requestTimelineUpdate("older", postsPerRefresh, followingUsers);
}
}
}
function encode_utf8(s) {
// only needed in android 2.3 - why?
var ua = navigator.userAgent;
if( ua.indexOf("Android") >= 0 )
{
var androidversion = parseFloat(ua.slice(ua.indexOf("Android")+8));
if (androidversion < 3.0)
{
return unescape(encodeURIComponent(s));
}
}
return s;
}
var tmobileQueryReq;
function setupHashtagOrMention(board, query, resource) {
$.mobile.loading('show');
board.empty();
tmobileQueryReq = queryStart(board, query, resource, undefined, undefined, {
boardAutoAppend: true,
skidoo: function (req) {
var curPage = $.mobile.activePage.attr('id');
return (curPage !== 'mentions' && curPage !== 'hashtag') || req !== tmobileQueryReq;
}
});
}
// every 2 seconds do something page specific.
function tmobileTick() {
var curPage = $.mobile.activePage.attr("id");
if( curPage == "network" ) {
networkUpdate();
}
if( curPage == "home" ) {
requestLastHave();
}
if( curPage == "new-user-modal" ) {
dumpPubkey(defaultScreenName, function(args, pubkey) {
//pubkey = "";
if( pubkey.length > 0 ) {
follow('twister', true, function() {
$.MAL.goProfileEdit();
});
}
}, {} );
}
}
$(document).on('mobileinit', function () {
$.mobile.allowCrossDomainPages = true;
$.mobile.zoom.enabled = false;
$.mobile.buttonMarkup.hoverDelay = 0; //defaults 200
$.mobile.defaultDialogTransition = 'none';
$.mobile.defaultPageTransition = 'none';
});