/* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Q V I T T E R · · · · http://github.com/hannesmannerheim/qvitter · · · · · · \\\\_\ · · \\) \____) · · · · · · · · Qvitter is free software: you can redistribute it and / or modify it · · under the terms of the GNU Affero General Public License as published by · · the Free Software Foundation, either version three of the License or (at · · your option) any later version. · · · · Qvitter is distributed in hope that it will be useful but WITHOUT ANY · · WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS · · FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for · · more details. · · · · You should have received a copy of the GNU Affero General Public License · · along with Qvitter. If not, see . · · · · Contact h@nnesmannerhe.im if you have any questions. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */ /* · · · Update stream on back button (if we're using history push state) · · · · · · · · · · · · · · */ if(window.useHistoryPushState) { window.onpopstate = function(event) { if(event && event.state) { display_spinner(); setNewCurrentStream(event.state.strm,function(){ remove_spinner(); },false); } } } /* · · · fix login and register box to top when they reach top · · · · · · · · · · · · · · */ window.loginContentStartPos = $('.front-welcome-text').height()+45; $(window).scroll(function(e){ if ($(this).scrollTop() > window.loginContentStartPos && $('#login-content').css('position') != 'fixed'){ $('#login-content, .front-signup').not('#popup-signup').css({'position': 'fixed', 'top': '50px'}); } else if ($(this).scrollTop() < window.loginContentStartPos && $('#login-content').css('position') != 'absolute'){ $('#login-content, .front-signup').not('#popup-signup').css({'position': 'absolute', 'top': 'auto'}); } }); /* · · · Tooltip to show what federated means · · · · · · · · · · · · · · */ $('#federated-tooltip').on('mouseenter',function(){ $('#what-is-federation').fadeIn(100); }); $('#what-is-federation').on('mouseleave',function(){ $('#what-is-federation').fadeOut(100); }); /* · · · Register · · · · · · · · · · · · · · */ $('.front-signup input, .front-signup button').removeAttr('disabled'); // clear this onload $('#signup-btn-step1').click(function(){ display_spinner(); $('.front-signup input, .front-signup button').addClass('disabled'); $('.front-signup input, .front-signup button').attr('disabled','disabled'); // 7 s timeout to annoy human spammers setTimeout(function(){ remove_spinner(); popUpAction('popup-register',window.sL.signUp,'',false); // ask api if nickname is ok, if no typing for 1 s $('#signup-user-nickname-step2').on('keyup',function(){ clearTimeout(window.checkNicknameTimeout); if($('#signup-user-nickname-step2').val().length>1 && /^[a-zA-Z0-9]+$/.test($('#signup-user-nickname-step2').val())) { $('#signup-user-nickname-step2').addClass('nickname-taken'); if($('.spinner-wrap').length==0) { $('#signup-user-nickname-step2').after('
'); } window.checkNicknameTimeout = setTimeout(function(){ getFromAPI('check_nickname.json?nickname=' + encodeURIComponent($('#signup-user-nickname-step2').val()),function(data){ $('.spinner-wrap').remove(); console.log($('.spinner-wrap').length); if(data==0) { $('#signup-user-password2-step2').trigger('keyup'); // revalidates } else { $('#signup-user-nickname-step2').removeClass('nickname-taken'); $('#signup-user-password2-step2').trigger('keyup'); } }); },1000); } else { $('.spinner-wrap').remove(); } }); // validate on keyup $('#popup-register input').on('keyup',function(){ if(validateRegisterForm($('#popup-register'))) { if(!$('#signup-user-nickname-step2').hasClass('nickname-taken')) { $('#signup-btn-step2').removeClass('disabled'); } else { $('#signup-btn-step2').addClass('disabled'); } } else { $('#signup-btn-step2').addClass('disabled'); } }); $('#popup-register input').trigger('keyup'); // submit on enter $('input#signup-user-name-step2,input#signup-user-email-step2,input#signup-user-password1-step2, input#signup-user-password2-step2').keyup(function(e){ if(e.keyCode==13) { $('#signup-btn-step2').trigger('click'); } }); $('#signup-btn-step2').click(function(){ $('#popup-register input,#popup-register button').addClass('disabled'); display_spinner(); $.ajax({ url: window.fullUrlToThisQvitterApp + 'API.php', type: "POST", data: { postRequest: 'account/register.json', nickname: $('#signup-user-nickname-step2').val(), email: $('#signup-user-email-step2').val(), fullname: $('#signup-user-name-step2').val(), homepage: $('#signup-user-homepage-step2').val(), bio: $('#signup-user-bio-step2').val(), location: $('#signup-user-location-step2').val(), password: $('#signup-user-password1-step2').val(), confirm: $('#signup-user-password2-step2').val(), username: 'none', }, dataType:"json", error: function(data){ console.log('error'); console.log(data); }, success: function(data) { remove_spinner(); if(typeof data.error == 'undefined') { $('input#username').val($('#signup-user-nickname-step2').val()); $('input#password').val($('#signup-user-password1-step2').val()); $('input#rememberme').prop('checked', true); $('#submit-login').trigger('click'); $('#popup-register').remove(); } else { alert('Try again! ' + data.error); $('#popup-register input,#popup-register button').removeClass('disabled'); } } }); }); // reactivate register form on popup close $('#popup-register').on('remove',function(){ $('.front-signup input, .front-signup button').removeAttr('disabled'); $('.front-signup input, .front-signup button').removeClass('disabled'); }); },7000); }); // submit on enter $('input#signup-user-name,input#signup-user-email,input#signup-user-password').keyup(function(e){ if(e.keyCode==13) { $('#signup-btn-step1').trigger('click'); } }); /* · · · autologin or show welcome screen · · · · · · · · · · · · · · */ $('#submit-login').removeAttr('disabled'); // might be remebered by browser... $(window).load(function() { $('#user-container').css('display','block'); $('#feed').css('display','block'); // check for localstorage, if none, we remove possibility to remember login var userInLocalStorage = false; if(localStorageIsEnabled()) { if(typeof localStorage.autologinUsername != 'undefined') { userInLocalStorage = true; } } else { $('input#rememberme').css('display','none'); $('span#rememberme_label').css('display','none'); $('#remember-forgot').css('font-size','0'); $('.language-dropdown').css('display','none'); } // autologin if saved if(userInLocalStorage) { $('input#username').val(localStorage.autologinUsername); $('input#password').val(localStorage.autologinPassword); $('#submit-login').trigger('click'); } else { display_spinner(); window.currentStream = ''; // force reload stream setNewCurrentStream(getStreamFromUrl(),function(){ logoutWithoutReload(false); remove_spinner(); },true); } }); /* · · · Login action · · · · · · · · · · · · · · */ $('#submit-login').click(function () { $('#submit-login').attr('disabled','disabled'); $('#submit-login').focus(); // prevents submit on enter to close alert-popup on wrong credentials display_spinner(); // login with ajax checkLogin($('input#username').val(),$('input#password').val(),function(user){ console.log(user); // store credentials in global var window.loginUsername = user.screen_name; window.loginPassword = $('input#password').val(); // set colors if the api supports it if(typeof user.linkcolor != 'undefined' && typeof user.backgroundcolor != 'undefined') { user.linkcolor = user.linkcolor || ''; // no null value user.backgroundcolor = user.backgroundcolor || ''; // no null value window.userLinkColor = user.linkcolor; window.userBackgroundColor = user.backgroundcolor; if(window.userLinkColor.length != 6) { window.userLinkColor = window.defaultLinkColor; } if(window.userBackgroundColor.length != 6) { window.userBackgroundColor = window.defaultBackgroundColor; } } // add user data to DOM, show search form, remeber user id, show the feed $('#user-avatar').attr('src', user.profile_image_url); $('#user-name').append(user.name); $('#user-screen-name').append(user.screen_name); $('#user-profile-link').append('' + window.sL.viewMyProfilePage + ''); $('#user-queets strong').html(user.statuses_count); $('#user-following strong').html(user.friends_count); $('#user-followers strong').html(user.followers_count); $('#user-groups strong').html(user.groups_count); window.myUserID = user.id; // if remeber me is checked, save credentials in local storage if($('#rememberme').is(':checked')) { if(localStorageIsEnabled()) { localStorage.autologinPassword = $('input#password').val(); localStorage.autologinUsername = $('input#username').val(); } } // load history loadHistoryFromLocalStorage(); // if this is a special url for user, notice etc, grab that stream var streamToSet = getStreamFromUrl(); // if this is the public feed, we redirect to friends_timline (I think that's intuitive) if(streamToSet == 'statuses/public_timeline.json') { streamToSet = 'statuses/friends_timeline.json'; } // set stream window.currentStream = ''; // always reload stream on login setNewCurrentStream(streamToSet,function(){ $('.language-dropdown').css('display','none'); $('.dropdown-menu.quitter-settings li.language').css('display','block'); $('#user-header').animate({opacity:'1'},800); $('#user-body').animate({opacity:'1'},800); $('#user-footer').animate({opacity:'1'},800); $('.menu-container').animate({opacity:'1'},800); $('#page-container').animate({opacity:'1'},200); $('.front-welcome-text').slideUp(1000); $('#settingslink').fadeIn('slow'); $('#search').fadeIn('slow'); $('#login-content').css('display','none'); $('.front-signup').css('display','none'); remove_spinner(); },true); }); }); /* · · · In the login form, we want to check the remember-me-checkbox when its label is clicked · · · · · · · · · · · · · · */ $('#rememberme_label').click(function(){ if($('#rememberme').prop('checked')) { $('#rememberme').prop('checked', false); } else { $('#rememberme').prop('checked', true); } }); $('#rememberme_label').disableSelection(); /* · · · Submit login form on enter key · · · · · · · · · · · · · · */ $('input#username,input#password,input#rememberme').keyup(function(e){ if(e.keyCode==13) { $('#submit-login').trigger('click'); } }); /* · · · Logout by deleting local storage credentials (if there are any) and reload · · · · · · · · · · · · · · */ $('#logout').click(function(){ if(localStorageIsEnabled()) { delete localStorage.autologinUsername; delete localStorage.autologinPassword; } location.reload(); }); /* · · · Settings · · · · · · · · · · · · · · */ $('#settings').click(function(){ // buttons to add later: '
' popUpAction('popup-settings', window.sL.settings,'
',false); $('#link-color-selection').minicolors({ change: function(hex) { changeLinkColor(hex); postNewLinkColor(hex.substring(1)); } }); $('#background-color-selection').minicolors({ change: function(hex) { $('body').css('background-color',hex); postNewBackgroundColor(hex.substring(1)); } }); }); /* · · · Do a logout without reloading, i.e. on login errors · · · · · · · · · · · · · · */ function logoutWithoutReload(doShake) { if(window.currentStream == 'statuses/public_timeline.json') { $('body').css('background-image', 'url(' + window.fullUrlToThisQvitterApp + 'img/ekan4.jpg)'); } $('#submit-login').removeAttr('disabled'); // delete any locally stored credentials if(localStorageIsEnabled()) { delete localStorage.autologinUsername; delete localStorage.autologinPassword; } $('#user-header').animate({opacity:'0'},200); $('#user-body').animate({opacity:'0'},200); $('#user-footer').animate({opacity:'0'},200); $('.menu-container').animate({opacity:'0'},200); $('.language-dropdown').css('display','block'); $('.dropdown-menu.quitter-settings li.language').css('display','none'); $('#settingslink').fadeOut('slow'); $('#search').fadeOut('slow'); $('input#username').focus(); $('.front-signup').animate({opacity:'1'},200); if(doShake) { $('input#username').css('background-color','pink'); $('input#password').css('background-color','pink'); } $('#login-content').animate({opacity:'1'},200, function(){ if(doShake) { $('#login-content').effect('shake',{distance:5,times:2},function(){ $('input#username').animate({backgroundColor:'#fff'},1000); $('input#password').animate({backgroundColor:'#fff'},1000); }); } $('.front-welcome-text').fadeIn(3000); }); $('#page-container').animate({opacity:'1'},200); } /* · · · Handling the language dropdown selection · · · · · · · · · · · · · · */ $('.dropdown').click(function(){$(this).toggleClass('dropped')}); $('.dropdown').disableSelection(); $(document).bind('click', function (e) { if(!$(e.target).is('#logo') && !$(e.target).is('#settingslink') && !$(e.target).is('.nav-session') && !$(e.target).is('.dropdown-toggle') && !$(e.target).is('.dropdown-toggle small') && !$(e.target).is('.dropdown-toggle span') && !$(e.target).is('.dropdown-toggle b')) { $('.dropdown').removeClass('dropped'); $('.quitter-settings.dropdown-menu').removeClass('dropped'); } }); $('.language-link').click(function(){ if(localStorageIsEnabled()) { localStorage.selectedLanguage = $(this).attr('data-lang-code'); // save langage selection } location.reload(); // reload }); /* · · · Show the logo menu dropdown on click · · · · · · · · · · · · · · */ $('#settingslink').click(function(){ if(!$('.quitter-settings').hasClass('dropped')) { $('.quitter-settings').addClass('dropped'); } else { $('.quitter-settings').removeClass('dropped'); } }); /* · · · When clicking a follow button · · · · · · · · · · · · · · */ $('body').on('click','.follow-button',function(event){ if(!$(this).hasClass('disabled')) { $(this).addClass('disabled'); // get user id var user_id = $(this).attr('data-follow-user-id'); // follow or unfollow? if($(this).hasClass('following')) { var followOrUnfollow = 'unfollow'; } else { var followOrUnfollow = 'follow'; } // post to api display_spinner(); APIFollowOrUnfollowUser(followOrUnfollow,user_id, this, function(data,this_element) { remove_spinner(); $(this_element).removeClass('disabled'); if(data) { if(data.following) { $(this_element).addClass('following'); $('#user-following strong').html(parseInt($('#user-following strong').html(),10)+1); } else { $(this_element).removeClass('following'); $('#user-following strong').html(parseInt($('#user-following strong').html(),10)-1); } } }); } }); /* · · · When clicking a join group button · · · · · · · · · · · · · · */ $('body').on('click','.member-button',function(event){ if(!$(this).hasClass('disabled')) { $(this).addClass('disabled'); // get group id var group_id = $(this).attr('data-group-id'); // join or leave? if($(this).hasClass('member')) { var joinOrLeave = 'leave'; } else { var joinOrLeave = 'join'; } // post to api display_spinner(); APIJoinOrLeaveGroup(joinOrLeave,group_id, this, function(data,this_element) { remove_spinner(); $(this_element).removeClass('disabled'); if(data) { if(data.member) { $(this_element).addClass('member'); $('.profile-card .member-stats strong').html(parseInt($('.profile-card .member-stats strong').html(),10)+1); $('#user-groups strong').html(parseInt($('#user-groups strong').html(),10)+1); } else if(data.member === false) { $(this_element).removeClass('member'); $('.profile-card .member-stats strong').html(parseInt($('.profile-card .member-stats strong').html(),10)-1); $('#user-groups strong').html(parseInt($('#user-groups strong').html(),10)-1); } } }); } }); /* · · · Select a stream when clicking on a menu item · · · · · · · · · · · · · · */ // select stream $('body').on('click','.stream-selection',function(event){ if(!$(event.target).is('.close-right') && !$(this).hasClass('current')) { setNewCurrentStream($(this).attr('data-stream-name'),function(){},true); } }); /* · · · Select a stream when the logged in user clicks their own queets, followers etc · · · · · · · · · · · · · · */ $('#user-header, #user-queets, #user-following, #user-followers, #user-groups').on('click',function(){ if($(this).attr('id') == 'user-header' || $(this).attr('id') == 'user-queets') { setNewCurrentStream('statuses/user_timeline.json?screen_name=' + window.loginUsername,function(){},true); } else if($(this).attr('id') == 'user-following') { setNewCurrentStream('statuses/friends.json?count=20',function(){},true); } else if($(this).attr('id') == 'user-followers') { setNewCurrentStream('statuses/followers.json?count=20',function(){},true); } else if($(this).attr('id') == 'user-groups') { setNewCurrentStream('statusnet/groups/list.json?count=10',function(){},true); } }); /* · · · Select a stream when clicking on queets, followers etc in a profile card or feed header · · · · · · · · · · · · · · */ $('body').on('click','.profile-banner-footer .stats li a, .queet-stream',function(){ var screenName = $('.profile-card-inner .screen-name').html().substring(1); if($(this).hasClass('tweet-stats')) { setNewCurrentStream('statuses/user_timeline.json?screen_name=' + screenName,function(){},true); } else if($(this).hasClass('following-stats')) { setNewCurrentStream('statuses/friends.json?count=20&screen_name=' + screenName,function(){},true); } else if($(this).hasClass('follower-stats')) { setNewCurrentStream('statuses/followers.json?count=20&screen_name=' + screenName,function(){},true); } else if($(this).hasClass('groups-stats')) { setNewCurrentStream('statusnet/groups/list.json?count=10&screen_name=' + screenName,function(){},true); } else if($(this).hasClass('queets')) { setNewCurrentStream('statuses/user_timeline.json?screen_name=' + screenName,function(){},true); } else if($(this).hasClass('mentions')) { setNewCurrentStream('statuses/mentions.json?screen_name=' + screenName,function(){},true); } else if($(this).hasClass('favorites')) { setNewCurrentStream('favorites.json?screen_name=' + screenName,function(){},true); } else if($(this).hasClass('member-stats')) { setNewCurrentStream('statusnet/groups/membership/' + screenName + '.json?count=20',function(){},true); } else if($(this).hasClass('admin-stats')) { setNewCurrentStream('statusnet/groups/admins/' + screenName + '.json?count=20',function(){},true); } }); /* · · · Searching · · · · · · · · · · · · · · */ $('#search-query').on('keyup',function(e) { if(e.keyCode==13) { showSearchStream(); }}); // on enter in input field $('button.icon.nav-search').on('click',function(e) { showSearchStream();}); // on click on magnifying glass function showSearchStream() { streamName = 'search.json?q=' + encodeURIComponent($('#search-query').val()); setNewCurrentStream(streamName,function(){},true); } /* · · -1) { e.preventDefault(); setNewCurrentStream('statusnet/tags/timeline/' + $(this).text().toLowerCase() + '.json',function(){},true); } // groups else if (/^[0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/group/','').replace('/id',''))) { e.preventDefault(); if($(this).hasClass('account-group')) { var groupName = $(this).find('.screen-name').html().substring(1); } else { var groupName = $(this).text().toLowerCase(); } setNewCurrentStream('statusnet/groups/timeline/' + groupName + '.json',function(){},true); } else if ($(this).attr('href').indexOf(window.siteRootDomain + '/group/')>-1) { e.preventDefault(); setNewCurrentStream('statusnet/groups/timeline/' + $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/group/','') + '.json',function(){},true); } // profile picture else if ($(this).hasClass('profile-picture')) { e.preventDefault(); popUpAction('popup-profile-picture', $('.profile-card-inner .screen-name').html(),'',false); } // external profiles else if (($(this).children('span.mention').length>0 // if it's a mention || ($(this).hasClass('account-group') && $(this).attr('href').indexOf('/group/')==-1) // or if this is queet stream item header but not a group || ($(this).closest('.stream-item').hasClass('activity') && $(this).attr('href').indexOf('/group/')==-1)) // or if it's a activity notice but not a group link && typeof window.loginUsername != 'undefined') { // if logged in e.preventDefault(); display_spinner(); getFromAPI('externalprofile/show.json?profileurl=' + encodeURIComponent($(this).attr('href')),function(data){ // external user found locally if(data) { var screenNameWithServer = '@' + data.screen_name + '@' + data.statusnet_profile_url.replace('http://','').replace('https://','').replace('/' + data.screen_name,''); // empty strings and zeros instead of null data.name = data.name || ''; data.profile_image_url = data.profile_image_url || ''; data.profile_image_url_profile_size = data.profile_image_url_profile_size || ''; data.profile_image_url_original = data.profile_image_url_original || ''; data.screen_name = data.screen_name || ''; data.description = data.description || ''; data.location = data.location || ''; data.url = data.url || ''; data.statusnet_profile_url = data.statusnet_profile_url || ''; data.statuses_count = data.statuses_count || 0; data.followers_count = data.followers_count || 0; data.friends_count = data.friends_count || 0; // profile card var followingClass = ''; if(data.following) { followingClass = 'following'; } var followButton = ''; var profileCard = '
'; popUpAction('popup-external-profile', screenNameWithServer,profileCard,false); remove_spinner(); } // external user not found locally, try externally else { // TODO! } }); } // external groups else if (($(this).children('span.group').length>0 // if it's a group mention || ($(this).hasClass('account-group') && $(this).attr('href').indexOf('/group/')>-1) // or if this is group stream item header || ($(this).closest('.stream-item').hasClass('activity') && $(this).attr('href').indexOf('/group/')>-1)) // or if it's a activity notice && typeof window.loginUsername != 'undefined') { // if logged in e.preventDefault(); display_spinner(); getFromAPI('statusnet/groups/show.json?id=foo&uri=' + encodeURIComponent($(this).attr('href')), function(data){ if(data){ data.nickname = data.nickname || ''; data.fullname = data.fullname || ''; data.stream_logo = data.stream_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-stream.png'; data.homepage_logo = data.homepage_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-profile.png'; data.original_logo = data.original_logo || 'http://quitter.se/theme/quitter-theme2/default-avatar-profile.png'; data.description = data.description || ''; data.homepage = data.homepage || ''; data.url = data.url || ''; data.member_count = data.member_count || 0; data.admin_count = data.admin_count || 0; // show user actions if logged in var memberClass = ''; if(data.member) { memberClass = 'member'; } var groupRoot = data.url.substring(0,data.url.indexOf('/group/')); var groupServer = groupRoot.replace('http://','').replace('https://',''); var memberButton = ''; // get local member avatars getFromAPI('statusnet/groups/membership.json?id=' + data.id, function(user_data){ if(user_data){ var avatars = ''; var i=0; $.each(user_data,function(k,v){ if(i<7) { avatars = avatars + ''; } i++; }); var profileCard = ''; popUpAction('popup-external-group-profile', '!' + data.nickname + '@' + groupServer,profileCard,false); remove_spinner(); }}); }}); } } }); /* · · · When user clicks the x to remove a menu history item · · · · · · · · · · · · · · */ $('body').on('click','.close-right',function(event){ $(this).parent('.stream-selection').remove(); updateHistoryLocalStorage(); }); /* · · · When sorting the history menu · · · · · · · · · · · · · · */ $('#history-container').on("sortupdate", function() { updateHistoryLocalStorage(); }); /* · · · Load more from the current stream when scroll is 1000px from bottom · · The search API is crap and don't do max_id and last_id, so we have to do pages there... · · · · · · · · · · · · · · */ $(window).scroll(function() { if($(window).scrollTop() + $(window).height() > $(document).height() - 1000) { // not if we're already loading if(!$('body').hasClass('loading-older')) { $('body').addClass('loading-older'); // remove loading class in 10 seconds, i.e. try again if failed to load within 10 s if(window.currentStream.substring(0,6) != 'search') { setTimeout(function(){$('body').removeClass('loading-older');},10000); } var lastStreamItemId = $('#feed-body').children('.stream-item').last().attr('id'); // if this is search or users lists, we need page and rpp vars, we store page number in an attribute if(window.currentStream.substring(0,6) == 'search' || window.currentStream.substring(0,23) == 'statuses/followers.json' || window.currentStream.substring(0,21) == 'statuses/friends.json' || window.currentStream.substring(0,26) == 'statusnet/groups/list.json' || window.currentStream.substring(0,28) == 'statusnet/groups/membership/' || window.currentStream.substring(0,24) == 'statusnet/groups/admins/') { if(typeof $('#feed-body').attr('data-search-page-number') != 'undefined') { var searchPage = parseInt($('#feed-body').attr('data-search-page-number'),10); } else { var searchPage=2; } var nextPage = searchPage+1; var getVars = qOrAmp(window.currentStream) + 'rpp=20&page=' + searchPage; // search uses 'rrp' var and others 'count' for paging, though we can add rrp to others aswell without any problem } // normal streams else { var getVars = qOrAmp(window.currentStream) + 'max_id=' + $('#feed-body').children('.stream-item').last().attr('data-quitter-id-in-stream'); } display_spinner(); getFromAPI(window.currentStream + getVars,function(data){ if(data) { addToFeed(data, lastStreamItemId,'visible'); $('body').removeClass('loading-older'); // if this is search our group users lists, we remember page number if(window.currentStream.substring(0,6) == 'search' || window.currentStream.substring(0,23) == 'statuses/followers.json' || window.currentStream.substring(0,21) == 'statuses/friends.json' || window.currentStream.substring(0,26) == 'statusnet/groups/list.json' || window.currentStream.substring(0,28) == 'statusnet/groups/membership/' || window.currentStream.substring(0,24) == 'statusnet/groups/admins/') { $('#feed-body').attr('data-search-page-number',nextPage); } remove_spinner(); } }); } } }); /* · · · Updates all queets' times/dates · · · · · · · · · · · · · · */ var updateTimesInterval=self.setInterval(function(){ $('.created-at').each(function(){ $(this).children('a').html(parseTwitterDate($(this).attr('data-created-at'))); }); },10000); /* · · · Check for new queets · · · · · · · · · · · · · · */ var checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling); function checkForNewQueets() { // no new requests if requests are very slow, e.g. searches if(!$('body').hasClass('loading-newer')) { $('body').addClass('loading-newer'); // only of logged in and not user stream if($('#user-container').css('display') == 'block' && $('.stream-item.user').length==0) { var lastId = $('#feed-body').children('.stream-item').not('.temp-post').attr('data-quitter-id-in-stream'); var addThisStream = window.currentStream; getFromAPI(addThisStream + qOrAmp(window.currentStream) + 'since_id=' + lastId,function(data){ if(data) { $('body').removeClass('loading-newer'); if(addThisStream == window.currentStream) { addToFeed(data, false, 'hidden'); } } }); } // if we have hidden items, show new-queets-bar if($('#feed-body').find('.stream-item.hidden').length > 0) { var new_queets_num = $('#feed-body').find('.stream-item.hidden').length; document.title = window.siteTitle + ' (' + new_queets_num + ')'; $('#new-queets-bar').parent().removeClass('hidden'); // text plural if(new_queets_num == 1) { var q_txt = ' ' + window.sL.newQueet; } else { var q_txt = ' ' + window.sL.newQueets; } $('#new-queets-bar').html(new_queets_num + q_txt); } } } /* · · · Show hidden queets when user clicks on new-queets-bar · · · · · · · · · · · · · · */ $('#feed').on('click','#new-queets-bar',function(){ document.title = window.siteTitle; $('.stream-item.hidden').css('opacity','0') $('.stream-item.hidden').animate({opacity:'1'}, 200); $('.stream-item.hidden').removeClass('hidden'); $('#new-queets-bar').parent().addClass('hidden'); }); /* · · · Expand and de-expand queets when clicking anywhere but on a few element types · · · · · · · · · · · · · · */ $('#feed-body').on('click','.queet',function (event) { if(!$(event.target).is('a') && !$(event.target).is('.name') && !$(event.target).is('.queet-box-template') && !$(event.target).is('button') && !$(event.target).is('.show-full-conversation') && !$(event.target).is('span.mention') && !$(event.target).is('.action-reply-container a span') && !$(event.target).is('.action-reply-container a b') && !$(event.target).is('.action-rt-container a span') && !$(event.target).is('.action-rt-container a b') && !$(event.target).is('.action-del-container a span') && !$(event.target).is('.action-del-container a b') && !$(event.target).is('.action-fav-container a span') && !$(event.target).is('.action-fav-container a b') && !$(event.target).is('span.group') && !$(event.target).is('.longdate') && !$(event.target).is('.screen-name') && !$(this).parent('.stream-item').hasClass('user')) { // not if user stream expand_queet($(this).parent()); } }); /* · · · When clicking the delete-button · · · · · · · · · · · · · · */ $('#feed').on('click','.action-del-container',function(){ var this_stream_item = $(this).parent().parent().parent().parent().parent(); var this_qid = this_stream_item.attr('data-quitter-id'); var $queetHtml = $('
').append(this_stream_item.html()); var $stuffToRemove = $queetHtml.find('.stream-item-footer, .expanded-content, .inline-reply-queetbox, .stream-item.conversation, .view-more-container-top, .view-more-container-bottom'); $stuffToRemove.remove(); var queetHtmlWithoutFooterAndConversation = $queetHtml.html(); popUpAction('popup-delete-' + this_qid, window.sL.deleteConfirmation,queetHtmlWithoutFooterAndConversation,'
'); $('#popup-delete-' + this_qid + ' button.primary').on('click',function(){ display_spinner(); $('.modal-container').remove(); // delete postActionToAPI('statuses/destroy/' + this_qid + '.json', function(data) { if(data) { remove_spinner(); // remove the stream-item clicked and all other displays of this object from dom (e.g. in conversation) $('.stream-item[data-quitter-id="' + this_qid + '"]').find('.queet').animate({opacity:'0'},700,function(){ $('.stream-item[data-quitter-id="' + this_qid + '"]').remove(); }); } else { remove_spinner(); } }); }); }); /* · · · When clicking the requeet-button · · · · · · · · · · · · · · */ $('#feed').on('click','.action-rt-container',function(){ var this_stream_item = $(this).parent().parent().parent().parent().parent(); var this_action = $(this); // requeet if(!this_action.children('.with-icn').hasClass('done')) { this_action.children('.with-icn').addClass('done'); this_action.find('.with-icn b').html(window.sL.requeetedVerb); this_stream_item.addClass('requeeted'); // post requeet postActionToAPI('statuses/retweet/' + this_stream_item.attr('data-quitter-id') + '.json', function(data) { if(data) { // success this_stream_item.attr('data-requeeted-by-me-id',data.id); } else { // error this_action.children('.with-icn').removeClass('done'); this_action.find('.with-icn b').html(window.sL.requeetVerb); this_stream_item.removeClass('requeeted'); } }); } // un-requeet else if(this_action.children('.with-icn').hasClass('done')) { display_spinner(); // if we don't have the id od the repeat stored in DOM, we need to look it up // (might be a problem if there's more than 100 repeats) if(typeof this_stream_item.attr('data-requeeted-by-me-id') == 'undefined') { getFavsOrRequeetsForQueet('requeets',this_stream_item.attr('data-quitter-id'),function(data) { $.each(data,function(key,obj){ if(window.myUserID == obj.user.id) { var my_rq_id = obj.id; unRequeet(this_stream_item, this_action, my_rq_id); } }); }); } // if we have the id stored in DOM else { var my_rq_id = this_stream_item.attr('data-requeeted-by-me-id'); unRequeet(this_stream_item, this_action, my_rq_id); } } }); /* · · · When clicking the fav-button · · · · · · · · · · · · · · */ $('#feed').on('click','.action-fav-container',function(){ var this_stream_item = $(this).parent().parent().parent().parent().parent(); var this_action = $(this); // fav if(!this_action.children('.with-icn').hasClass('done')) { this_action.children('.with-icn').addClass('done'); this_action.find('.with-icn b').html(window.sL.favoritedVerb); this_stream_item.addClass('favorited'); // post fav postActionToAPI('favorites/create/' + this_stream_item.attr('data-quitter-id') + '.json', function(data) { if(data) { // success } else { // error this_action.children('.with-icn').removeClass('done'); this_action.find('.with-icn b').html(window.sL.favoriteVerb); this_stream_item.removeClass('favorited'); } }); } // unfav else { display_spinner(); this_action.children('.with-icn').removeClass('done'); this_action.find('.with-icn b').html(window.sL.favoriteVerb); this_stream_item.removeClass('favorited'); // post unfav postActionToAPI('favorites/destroy/' + this_stream_item.attr('data-quitter-id') + '.json', function(data) { if(data) { // success remove_spinner(); } else { // error remove_spinner(); this_action.children('.with-icn').addClass('done'); this_action.find('.with-icn b').html(window.sL.favoritedVerb); this_stream_item.addClass('favorited'); } }); } }); /* · · · When clicking the reply-button · · · · · · · · · · · · · · */ $('#feed').on('click','.action-reply-container',function(){ var this_stream_item = $(this).parent().parent().parent().parent().parent(); var this_stream_item_id = this_stream_item.attr('data-quitter-id'); // if in conversation, popup if(this_stream_item.hasClass('conversation')) { var $queetHtml = $('
').append(this_stream_item.html()); var $queetHtmlFooter = $queetHtml.find('.stream-item-footer'); $queetHtmlFooter.remove(); var queetHtmlWithoutFooter = $queetHtml.html(); popUpAction('popup-reply-' + this_stream_item_id, window.sL.replyTo + ' ' + this_stream_item.find('.screen-name').html(),replyFormHtml(this_stream_item,this_stream_item_id),queetHtmlWithoutFooter); expandInlineQueetBox($('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.queet-box-template')); } // inline replies else { // if not expanded, expand first if(!this_stream_item.hasClass('expanded')) { expand_queet(this_stream_item); } // if queet box is not active: activate if(!this_stream_item.find('.queet').find('.queet-box-template').hasClass('active')) { expandInlineQueetBox(this_stream_item.find('.queet').find('.queet-box-template')); } } }); /* · · · Close popups · · · · · · · · · · · · · · */ $('body').on('click','.modal-container button.close',function(){ $('.modal-container').remove(); }); $('body').on('click','.modal-close',function(){ $('.modal-container').remove(); }); $(document).keyup(function(e){ if(e.keyCode==27) { $('.modal-container').remove(); } }); /* · · · Expand inline reply form when clicked · · · · · · · · · · · · · · */ $('#feed').on('click','.queet-box-template',function(){ // expand inline queet box expandInlineQueetBox($(this)); }); /* · · · When inline reply form blur, check if it is changed · · · · · · · · · · · · · · */ $('#feed').on('blur','.queet-box-template',function(){ if($(this).html().replace(/\s/g, '').replace(/ /gi,'').replace(/
/gi,'') != unescape($(this).attr('data-start-html')).replace(/\s/g, '').replace(/ /gi,'').replace(/
/gi,'')) { if($(this).text().replace(/\s/gi, '').replace(/ /gi,'').replace(/
/gi,'').length==0) { $(this).removeClass('active'); $(this).html(unescape($(this).attr('data-blurred-html'))); $(this).parent().find('.queet-toolbar').remove(); } } else { $(this).removeClass('active'); $(this).html(unescape($(this).attr('data-blurred-html'))); $(this).parent().find('.queet-toolbar').remove(); } }); /* · · · Do varouis thins on keyup in reply box, counting, checking for spaces in mentions etc · · · · · · · · · · · · · · */ $('body').on('keyup','.queet-box-template, .queet-box',function(e){ // count chars countCharsInQueetBox($(this),$(this).parent().find('.queet-toolbar .queet-counter'),$(this).parent().find('.queet-toolbar button')); // no spaces in mentions! $.each($(this).find('a'), function(key, obj){ var obj_html = $(obj).html(); var first_part = obj_html.substr(0,obj_html.indexOf(' ')); if(first_part.length>0) { var second_part = obj_html.substr(obj_html.indexOf(' ')+1); if(e.keyCode==32) { // space $(obj).before('' + first_part + ' '); $(obj).after(second_part); $(obj)[0].outerHTML = ''; } else { // other keys $(obj).before('' + first_part + ' ' + second_part); $(obj)[0].outerHTML = ''; } } }); }); /* · · · Post inline and popup replies · · · · · · · · · · · · · · */ $('body').on('click', '.queet-toolbar button',function () { if($(this).hasClass('enabled')) { // set temp post id if($('.temp-post').length == 0) { var tempPostId = 'stream-item-temp-post-i'; } else { var tempPostId = $('.temp-post').attr('id') + 'i'; } var queetText = $(this).parent().parent().parent().find('.queet-box-template').html(); var queetText_txt = $(this).parent().parent().parent().find('.queet-box-template').text(); // remove trailing
and convert other
to newline queetText = $.trim(queetText); if(queetText.substr(queetText.length-4) == '
') { queetText = queetText.substring(0, queetText.length - 4); queetText = queetText.replace(/
/g,"\n"); } // get reply to id and add temp queet if($('.modal-container').find('.queet-toolbar button').length>0) { // from popup var in_reply_to_status_id = $('.modal-container').attr('id').substring(12); // removes "popup-reply-" from popups id $('.modal-container').remove(); var queetHtml = '
'; queetHtml = detectRTL(queetHtml); $('#feed-body').prepend(queetHtml); } else { // from inline reply var in_reply_to_status_id = $(this).parent().parent().parent().parent().parent().attr('data-quitter-id'); var queetHtml = '
'; queetHtml = detectRTL(queetHtml); $(this).parent().parent().parent().parent().parent().append(queetHtml); } // null reply box $(this).parent().parent().parent().find('.queet-box-template').removeClass('active'); $(this).parent().parent().parent().find('.queet-box-template').html(unescape($(this).parent().parent().parent().find('.queet-box-template').attr('data-blurred-html'))); $(this).parent().parent().parent().find('.queet-toolbar').remove(); // check for new queets (one second from) NOW setTimeout('checkForNewQueets()', 1000); // post queet postReplyToAPI(queetText_txt, in_reply_to_status_id, function(data){ if(data) { // show real queet var new_queet = Array(); new_queet[0] = data; addToFeed(new_queet,tempPostId,'visible'); // remove temp queet $('#' + tempPostId).remove(); }}); } }); /* · · · Post queet · · · · · · · · · · · · · · */ $('#queet-toolbar button').click(function () { if($(this).hasClass('enabled')) { // set temp post id if($('.temp-post').length == 0) { var tempPostId = 'stream-item-temp-post-i'; } else { var tempPostId = $('.temp-post').attr('id') + 'i'; } var queetText = $('#queet-box').html(); // remove trailing
and convert other
to newline queetText = $.trim(queetText); if(queetText.substr(queetText.length-4) == '
') { queetText = queetText.substring(0, queetText.length - 4); queetText = queetText.replace(/
/g,"\n"); } // show temporary queet var queetHtml = '
'; // detect rtl queetHtml = detectRTL(queetHtml); $('#feed-body').prepend(queetHtml); // check for new queets (one second from) NOW setTimeout('checkForNewQueets()', 1000); // null post form $('#queet-box').html(window.sL.compose); $('#queet-box').attr('contenteditable','false'); $('#queet-toolbar').css('display','none'); // post queet postQueetToAPI(queetText, function(data){ if(data) { // show real queet var new_queet = Array(); new_queet[0] = data; addToFeed(new_queet,tempPostId,'visible'); // remove temp queet $('#' + tempPostId).remove(); }}); } }); /* · · · Count chars in queet box on keyup · · · · · · · · · · · · · · */ $('#queet-box').keyup(function () { countCharsInQueetBox($('#queet-box'),$('#queet-counter'),$('#queet-toolbar button')); }); /* · · · Expand/collapse queet box on click and blur · · · · · · · · · · · · · · */ $('#queet-box').click(function () { if($('#queet-box').html() == window.sL.compose) { $('#queet-box').attr('contenteditable','true'); $('#queet-box').html(' '); $('#queet-box').focus(); $('#queet-toolbar').css('display','block'); $('#queet-toolbar button').addClass('disabled'); countCharsInQueetBox($('#queet-box'),$('#queet-counter'),$('#queet-toolbar button')); } }); $('#queet-box').blur(function () { if($('#queet-box').html().length == 0 || $('#queet-box').html() == '
' || $('#queet-box').html() == '
' || $('#queet-box').html() == ' ' || $('#queet-box').html() == ' 
') { $('#queet-box').attr('contenteditable','false'); $('#queet-box').html(window.sL.compose); $('#queet-toolbar').css('display','none'); $('#queet-box').removeAttr('style'); } }); /* · · · Remove html and shorten urls on paste in queet boxes · · · · · · · · · · · · · · */ $('#queet-box').bind('paste',function () { $('#queet-box').css('color','transparent'); setTimeout(function () { // clean all html (but keep linebreaks) var $keep_br = $('
').append($('#queet-box').html().replace(/(
\s*)+$/,'').replace(/
/gi,'{{br}}')); $('#queet-box').html($keep_br.text().replace(/{{br}}/gi,'
')); // shorten urls // shortenUrlsInBox($('#queet-box'),$('#queet-counter'),$('#queet-toolbar button')); $('#queet-box').css('color','#333333'); placeCaretAtEnd(document.getElementById("queet-box")); countCharsInQueetBox($('#queet-box'),$('#queet-counter'),$('#queet-toolbar button')); }, 1); }); $('#feed').on('paste','.queet-box-template',function(e){ window.current_box_id = '#' + $(this).attr('id'); setTimeout(function () { // clean all html (but keep linebreaks) var $keep_br = $('
').append($(window.current_box_id).html().replace(/(
\s*)+$/,'').replace(/
/gi,'{{br}}')); $(window.current_box_id).html($keep_br.text().replace(/{{br}}/gi,'
')); // shorten urls // shortenUrlsInBox($(window.current_box_id),$(window.current_box_id).find('.queet-counter'),$(window.current_box_id).find('.queet-toolbar button')); placeCaretAtEnd(document.getElementById($(window.current_box_id).attr('id'))); countCharsInQueetBox($(window.current_box_id),$(window.current_box_id).find('.queet-counter'),$(window.current_box_id).find('.queet-toolbar button')); }, 1); }); /* · · · Shorten URL:s in queet boxes on space · · · · · · · · · · · · · · */ $('body').on('keyup','#queet-box',function(e){ if(e.keyCode == 32) { shortenUrlsInBox($('#queet-box'),$('#queet-counter'),$('#queet-toolbar button')); } }); $('#feed').on('keyup','.queet-box-template',function(e){ if(e.keyCode == 32) { shortenUrlsInBox($(this),$(this).find('.queet-counter'),$(this).find('.queet-toolbar button')); } }); /* · · · When clicking show more links, walk upwards or downwards · · · · · · · · · · · · · · */ $('#feed').on('click','.view-more-container-bottom', function(){ findReplyToStatusAndShow($(this).parent('.stream-item').attr('data-quitter-id'),$(this).attr('data-replies-after')); $(this).remove(); }); $('#feed').on('click','.view-more-container-top', function(){ var this_qid = $(this).closest('.stream-item:not(.conversation)').attr('data-quitter-id'); var queet = $(this).siblings('.queet'); rememberMyScrollPos(queet,'moretop' + this_qid); findInReplyToStatusAndShow($(this).parent('.stream-item').attr('data-quitter-id'),$(this).attr('data-trace-from'),false,true); $(this).remove(); backToMyScrollPos(queet,'moretop' + this_qid,false); // remove the "show full conversation" link if nothing more to show if($('#stream-item-' + $(this).parent('.stream-item').attr('data-quitter-id')).find('.hidden-conversation').length == 0) { $('#stream-item-' + $(this).parent('.stream-item').attr('data-quitter-id')).children('.queet').find('.show-full-conversation').remove(); } }); /* · · · When clicking "show full conversation", show all hidden queets in conversation · · · · · · · · · · · · · · */ $('#feed').on('click','.show-full-conversation',function(){ var this_q = $(this).closest('.queet'); var this_qid = $(this).closest('.stream-item:not(.conversation)').attr('data-quitter-id'); rememberMyScrollPos(this_q,this_qid); $('#stream-item-' + $(this).attr('data-stream-item-id')).find('.view-more-container-top').remove(); $('#stream-item-' + $(this).attr('data-stream-item-id')).find('.view-more-container-bottom').remove(); $.each($('#stream-item-' + $(this).attr('data-stream-item-id')).find('.hidden-conversation'),function(key,obj){ $(obj).removeClass('hidden-conversation'); $(obj).animate({opacity:'1'},400,function(){ $(obj).css('background-color','pink').animate({backgroundColor:'#F6F6F6'},1000); }); }); $(this).remove(); backToMyScrollPos(this_q,this_qid,false); });