better stream handling (hopefully..), and hover not hoover

This commit is contained in:
Hannes Mannerheim 2015-09-18 01:42:52 +02:00
parent c22eaa9f1b
commit df99f9bbaa
8 changed files with 700 additions and 792 deletions

View File

@ -66,7 +66,7 @@ class QvitterPlugin extends Plugin {
$settings['favicon'] = 'img/favicon.ico?v=5';
// DEFAULT SPRITE
$settings['sprite'] = Plugin::staticPath('Qvitter', '').'img/sprite.png?v=40';
$settings['sprite'] = Plugin::staticPath('Qvitter', '').'img/sprite.png?v=41';
// DEFAULT LINK COLOR
$settings['defaultlinkcolor'] = '#0084B4';
@ -307,22 +307,29 @@ class QvitterPlugin extends Plugin {
case 'api/statuses/user_timeline.json':
// add logged in user's user array
if (common_logged_in() && !isset($_GET['screen_name'])) {
if (common_logged_in() && !isset($_GET['screen_name']) && !isset($_GET['id'])) {
$profilecurrent = Profile::current();
header('Qvitter-User-Array: '.json_encode($this->qvitterTwitterUserArray($profilecurrent)));
}
// add screen_name's user array
elseif(isset($_GET['screen_name'])){
$screen_name_user = User::getKV('nickname', $_GET['screen_name']);
if($screen_name_user instanceof User) {
elseif(isset($_GET['screen_name']) || isset($_GET['id'])){
if(isset($_GET['screen_name'])) {
$user = User::getKV('nickname', $_GET['screen_name']);
}
elseif(isset($_GET['id'])) {
$user = User::getKV('id', $_GET['id']);
}
if($user instanceof User) {
if (common_logged_in()) {
$profilecurrent = Profile::current();
$currentuser = $profilecurrent->getUser();
header('Qvitter-User-Array: '.json_encode($this->qvitterTwitterUserArray($screen_name_user->getProfile(),$currentuser)));
header('Qvitter-User-Array: '.json_encode($this->qvitterTwitterUserArray($user->getProfile(),$currentuser)));
}
else {
header('Qvitter-User-Array: '.json_encode($this->qvitterTwitterUserArray($screen_name_user->getProfile())));
header('Qvitter-User-Array: '.json_encode($this->qvitterTwitterUserArray($user->getProfile())));
}
}
}

View File

@ -477,14 +477,19 @@ class QvitterAction extends ApiAction
</div>
</div>
</div>
<div class="menu-container">
<a class="stream-selection friends-timeline" data-stream-header="" data-stream-name="statuses/friends_timeline.json"><i class="chev-right"></i></a>
<a class="stream-selection notifications" data-stream-header="" data-stream-name="qvitter/statuses/notifications.json"><span id="unseen-notifications"></span><i class="chev-right"></i></a>
<a class="stream-selection mentions" data-stream-header="" data-stream-name="statuses/mentions.json"><i class="chev-right"></i></a>
<a class="stream-selection my-timeline" data-stream-header="@statuses/user_timeline.json" data-stream-name="statuses/user_timeline.json"><i class="chev-right"></i></a>
<a class="stream-selection favorites" data-stream-header="" data-stream-name="favorites.json"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>main/public" class="stream-selection public-timeline" data-stream-header="" data-stream-name="statuses/public_timeline.json"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>main/all" class="stream-selection public-and-external-timeline" data-stream-header="" data-stream-name="statuses/public_and_external_timeline.json"><i class="chev-right"></i></a>
<div class="menu-container"><?php
if($logged_in_user) {
?><a href="<?php print $instanceurl.$logged_in_user->nickname ?>/all" class="stream-selection friends-timeline"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl.$logged_in_user->nickname ?>/notifications" class="stream-selection notifications"><span id="unseen-notifications"></span><i class="chev-right"></i></a>
<a href="<?php print $instanceurl.$logged_in_user->nickname ?>/replies" class="stream-selection mentions"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl.$logged_in_user->nickname ?>" class="stream-selection my-timeline"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl.$logged_in_user->nickname ?>/favorites" class="stream-selection favorites"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>main/public" class="stream-selection public-timeline"><i class="chev-right"></i></a>
<a href="<?php print $instanceurl ?>main/all" class="stream-selection public-and-external-timeline"><i class="chev-right"></i></a>
<?php
}
?>
</div>
<div class="menu-container" id="bookmark-container"></div>
<div class="menu-container" id="history-container"></div>
@ -513,6 +518,7 @@ class QvitterAction extends ApiAction
<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/dom-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/dom-functions.js')); ?>"></script>
<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/misc-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/misc-functions.js')); ?>"></script>
<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/ajax-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/ajax-functions.js')); ?>"></script>
<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/stream-router.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/stream-router.js')); ?>"></script>
<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/qvitter.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/qvitter.js')); ?>"></script>
<?php

View File

@ -1337,7 +1337,7 @@ body.rtl #footer-spinner-container {
border-bottom:0 none;
}
.hoover-card {
.hover-card {
width: auto;
max-width: 290px;
line-height: 20px;
@ -1356,7 +1356,7 @@ body.rtl #footer-spinner-container {
word-break: break-all;
box-shadow: 0 0 10px rgba(0,0,0,0.4);
}
.hoover-card-caret {
.hover-card-caret {
z-index: 9999;
opacity:0;
display:block;
@ -1370,7 +1370,7 @@ body.rtl #footer-spinner-container {
border-right-color: transparent;
transition: opacity 0.1s ease-in 0;
}
.hoover-card-caret.bottom {
.hover-card-caret.bottom {
border-top:5px solid #fff;
border-bottom:0 none;
}
@ -2226,9 +2226,9 @@ body.rtl .view-more-container-bottom { direction:rtl; }
vertical-align: top;
}
.stream-item-header .addressees span:first-child:before {
content: "\f105";
content: "\00A0\f105";
display:inline-block;
padding:0 6px 0 2px;
padding:0 4px 0 2px;
font-size:12px;
font-family:FontAwesome;
font-style:normal;
@ -2687,12 +2687,12 @@ ul.stats li {
.profile-card ul.stats li {
padding-top: 7px;
}
.hoover-card .profile-card ul.stats li {
.hover-card .profile-card ul.stats li {
padding-top: 6px;
min-width:70px;
}
.hoover-card .profile-card ul.stats li.follower-num,
.hoover-card .profile-card ul.stats li.groups-num {
.hover-card .profile-card ul.stats li.follower-num,
.hover-card .profile-card ul.stats li.groups-num {
display:none;
}
.queet.rtl ul.stats li {
@ -2708,7 +2708,7 @@ ul.stats a {
line-height: 18px;
font-weight: normal;
}
.hoover-card ul.stats a {
.hover-card ul.stats a {
font-size: 9px;
}
.queet.rtl ul.stats a{
@ -2722,7 +2722,7 @@ ul.stats a strong {
line-height: 16px;
display: block;
}
.hoover-card ul.stats a strong {
.hover-card ul.stats a strong {
font-size: 17px;
}
@ -3467,7 +3467,7 @@ div.nav-session {
width: 588px;
}
.hoover-card .profile-card {
.hover-card .profile-card {
width:290px;
margin-bottom:0;
border:0 none;
@ -3495,7 +3495,7 @@ div.nav-session {
-o-background-size: cover;
background-size: cover;
}
.hoover-card .profile-header-inner {
.hover-card .profile-header-inner {
height: 200px;
}
.profile-header-inner a:hover {
@ -3514,7 +3514,7 @@ div.nav-session {
top: 60px;
width: 100%;
}
.hoover-card .profile-header-inner .profile-header-inner-overlay {
.hover-card .profile-header-inner .profile-header-inner-overlay {
height: 140px;
}
.profile-header-inner .profile-picture {
@ -3531,7 +3531,7 @@ div.nav-session {
z-index: 5;
}
.hoover-card .profile-header-inner .profile-picture {
.hover-card .profile-header-inner .profile-picture {
border: 2px solid #ffffff;
border-radius: 4px;
height: 40px;
@ -3545,7 +3545,7 @@ div.nav-session {
border-radius: 3px 3px 3px 3px;
float: none;
}
.hoover-card .profile-header-inner .profile-picture img {
.hover-card .profile-header-inner .profile-picture img {
border-radius: 3px;
height: 40px;
width: 40px;
@ -3576,7 +3576,7 @@ div.nav-session {
max-width:100%;
text-overflow: ellipsis;
}
.hoover-card .profile-card-inner .fullname {
.hover-card .profile-card-inner .fullname {
font-size: 14px;
font-weight: 700;
height: 26px;
@ -3601,7 +3601,7 @@ div.nav-session {
white-space: nowrap;
text-overflow: ellipsis;
}
.hoover-card .profile-header-inner .profile-card-inner h2.username {
.hover-card .profile-header-inner .profile-card-inner h2.username {
font-size: 14px;
line-height:18px;
margin-bottom: 4px;
@ -3632,7 +3632,7 @@ div.nav-session {
margin-left:7px;
text-transform:uppercase;
}
.hoover-card .profile-header-inner .profile-card-inner h2.username .follows-you {
.hover-card .profile-header-inner .profile-card-inner h2.username .follows-you {
background-color: rgba(0, 0, 0, 0.5);
bottom: -36px;
display: block;
@ -3658,7 +3658,7 @@ div.nav-session {
overflow: hidden;
text-overflow: ellipsis;
}
.hoover-card .profile-header-inner .profile-card-inner .bio-container p {
.hover-card .profile-header-inner .profile-card-inner .bio-container p {
font-size: 12px;
letter-spacing: 0.2px;
line-height: 15px;
@ -3672,8 +3672,8 @@ div.nav-session {
line-height: 18px;
margin:0;
}
.hoover-card .profile-header-inner .profile-card-inner .location-and-url,
.hoover-card .profile-header-inner .profile-card-inner .location-and-url input {
.hover-card .profile-header-inner .profile-card-inner .location-and-url,
.hover-card .profile-header-inner .profile-card-inner .location-and-url input {
font-size: 12px;
letter-spacing: 0.2px;
line-height: 15px;
@ -3713,7 +3713,7 @@ div.nav-session {
min-height: 52px;
position: relative;
}
.hoover-card .profile-banner-footer {
.hover-card .profile-banner-footer {
min-height: 47px;
}
.profile-banner-footer ul.stats {
@ -3725,13 +3725,13 @@ div.nav-session {
.profile-banner-footer ul.stats li a {
padding: 0 15px 8px 12px;
}
.hoover-card .profile-banner-footer ul.stats li a {
.hover-card .profile-banner-footer ul.stats li a {
padding-bottom: 5px;
}
.profile-banner-footer ul.stats li:first-child a {
padding-left: 12px;
}
.hoover-card .profile-banner-footer ul.stats li:first-child a {
.hover-card .profile-banner-footer ul.stats li:first-child a {
padding-left: 6px;
}
.profile-banner-footer ul.stats li a strong {
@ -3742,7 +3742,7 @@ div.nav-session {
float: right;
margin: 10px;
}
.hoover-card .profile-card .user-actions {
.hover-card .profile-card .user-actions {
margin-right: 5px;
margin-bottom: 5px;
}

View File

@ -151,7 +151,7 @@ function getFromAPI(stream, actionOnSuccess) {
if(request.getResponseHeader('Qvitter-User-Array') !== null) {
// while waiting for this data user might have changed stream, so only proceed if current stream still is this one
if(window.currentStream == stream.replace('&withuserarray=1','')) {
if(window.currentStream == stream) {
var qvitterUserArrayHeader = request.getResponseHeader('Qvitter-User-Array');
// quitter.se fix
@ -180,6 +180,27 @@ function getFromAPI(stream, actionOnSuccess) {
}
/* ·
·
· Get user nickname from user id
·
· @param id: local user id
· @param callback: function to invoke when done
·
· · · · · · · · · · · · · */
function getUserIdFromNicknameFromAPI(id, callback) {
getFromAPI('users/show.json?id=' + id, function(data){
if(data && typeof data.screen_name != 'undefined') {
callback(data.screen_name);
}
else {
callback(false);
}
});
}
/* ·
·
· Update the bookmarks

View File

@ -222,10 +222,10 @@ function buildProfileCard(data) {
</div>\
<div class="profile-banner-footer">\
<ul class="stats">\
<li class="tweet-num"><a class="tweet-stats">' + window.sL.notices + '<strong>' + data.statuses_count + '</strong></a></li>\
<li class="following-num"><a class="following-stats">' + window.sL.following + '<strong>' + data.friends_count + '</strong></a></li>\
<li class="follower-num"><a class="follower-stats">' + window.sL.followers + '<strong>' + data.followers_count + '</strong></a></li>\
<li class="groups-num"><a class="groups-stats">' + window.sL.groups + '<strong>' + data.groups_count + '</strong></a></li>\
<li class="tweet-num"><a href="' + data.statusnet_profile_url + '" class="tweet-stats">' + window.sL.notices + '<strong>' + data.statuses_count + '</strong></a></li>\
<li class="following-num"><a href="' + data.statusnet_profile_url + '/subscriptions" class="following-stats">' + window.sL.following + '<strong>' + data.friends_count + '</strong></a></li>\
<li class="follower-num"><a href="' + data.statusnet_profile_url + '/subscribers" class="follower-stats">' + window.sL.followers + '<strong>' + data.followers_count + '</strong></a></li>\
<li class="groups-num"><a href="' + data.statusnet_profile_url + '/groups" class="groups-stats">' + window.sL.groups + '<strong>' + data.groups_count + '</strong></a></li>\
</ul>\
' + followButton + '\
<div class="clearfix"></div>\
@ -427,7 +427,52 @@ function groupProfileCard(groupAlias) {
// add card to DOM
$('#feed').siblings('.profile-card').remove(); // remove any old profile card
$('#feed').before('<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + data.original_logo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture" href="' + data.original_logo + '"><img src="' + data.homepage_logo + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + data.fullname + '<span></span></h1><h2 class="username"><span class="screen-name">!' + data.nickname + '</span></span></h2><div class="bio-container"><p>' + data.description + '</p></div><p class="location-and-url"></span><span class="url"><a href="' + data.homepage + '">' + data.homepage.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a class="member-stats">' + window.sL.memberCount + '<strong>' + data.member_count + '</strong></a></li><li><a class="admin-stats">' + window.sL.adminCount + '<strong>' + data.admin_count + '</strong></a></li></ul>' + memberButton + '<div class="clearfix"></div></div></div>');
console.log(data);
$('#feed').before(' <div class="profile-card group">\
<div class="profile-header-inner" style="background-image:url(' + data.original_logo + ')">\
<div class="profile-header-inner-overlay"></div>\
<a class="profile-picture" href="' + data.original_logo + '">\
<img src="' + data.homepage_logo + '" />\
</a>\
<div class="profile-card-inner">\
<a href="' + window.siteInstanceURL + 'group/' + data.nickname + '">\
<h1 class="fullname">sadsa\
' + data.fullname + '\
<span></span>\
</h1>\
<h2 class="username">\
<span class="screen-name">!' + data.nickname + '</span>\
</h2>\
</a>\
<div class="bio-container">\
<p>' + data.description + '</p>\
</div>\
<p class="location-and-url">\
<span class="url">\
<a href="' + data.homepage + '">' + data.homepage.replace('http://','').replace('https://','') + '</a>\
</span>\
</p>\
</div>\
</div>\
<div class="profile-banner-footer">\
<ul class="stats">\
<li>\
<a href="' + window.siteInstanceURL + 'group/' + data.nickname + '/members" class="member-stats">\
' + window.sL.memberCount + '\
<strong>' + data.member_count + '</strong>\
</a>\
</li>\
<li>\
<a href="' + window.siteInstanceURL + 'group/' + data.nickname + '/admins" class="admin-stats">\
' + window.sL.adminCount + '\
<strong>' + data.admin_count + '</strong>\
</a>\
</li>\
</ul>\
' + memberButton + '\
<div class="clearfix"></div>\
</div>\
</div>');
}});
}
@ -437,19 +482,24 @@ function groupProfileCard(groupAlias) {
·
· Change stream
·
· @param stream: part of the url to the api (everything after api base url)
· @param streamObject: object returned by pathToStreamRouter()
· @param actionOnSuccess: callback function on success
·
· · · · · · · · · */
function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
function setNewCurrentStream(streamObject,setLocation,actionOnSuccess) {
if(!streamObject && !streamObject.stream) {
console.log('invalid streamObject, no stream to set!');
return;
}
// remember state of old stream (including profile card)
window.oldStreams[window.currentStream] = $('#feed').siblings('.profile-card').outerHTML() + $('#feed').outerHTML();
// set location bar from stream
if(setLocation) {
setUrlFromStream(stream);
setUrlFromStream(streamObject);
}
// halt interval that checks for new queets
@ -467,97 +517,20 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
// null any searches
$('#feed-body').removeAttr('data-search-page-number');
// remember the most recent stream selection in global var
window.currentStream = stream;
// remember the most recent stream
window.currentStream = streamObject.stream;
window.currentStreamObject = streamObject;
// a @user stream, i.e. user's queets, user's followers, user's following, we set _queets_ as the default stream in the menu
if(stream.substring(0,45) == 'statuses/followers.json?count=20&screen_name='
|| stream.substring(0,43) == 'statuses/friends.json?count=20&screen_name='
|| stream.substring(0,48) == 'statusnet/groups/list.json?count=10&screen_name='
|| stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name='
|| stream.substring(0,27) == 'favorites.json?screen_name='
|| stream.substring(0,35) == 'statuses/mentions.json?screen_name='
|| stream.substring(0,27) == 'statuses/user_timeline.json') {
var defaultStreamName = 'statuses/user_timeline.json?' + stream.substring(stream.indexOf('screen_name='));
var streamHeader = '@' + stream.substring(stream.lastIndexOf('=')+1);
}
// my user streams, i.e. my followers, my following
else if(stream == 'statuses/followers.json?count=20'
|| stream == 'statuses/friends.json?count=20'
|| stream == 'statusnet/groups/list.json?count=10') {
var defaultStreamName = stream;
var streamHeader = '@' + window.loggedIn.screen_name;
}
// the default streams, get header from DOM
else if(stream == 'statuses/friends_timeline.json'
|| stream == 'statuses/mentions.json'
|| stream == 'qvitter/statuses/notifications.json'
|| stream == 'favorites.json'
|| stream == 'statuses/public_timeline.json'
|| stream == 'statuses/public_and_external_timeline.json') {
var defaultStreamName = stream;
var streamHeader = $('.stream-selection[data-stream-name="' + stream + '"]').attr('data-stream-header');
}
// !group stream
else if(stream.substring(0,26) == 'statusnet/groups/timeline/'
|| stream.substring(0,28) == 'statusnet/groups/membership/'
|| stream.substring(0,24) == 'statusnet/groups/admins/') {
var defaultStreamName = 'statusnet/groups/timeline/' + stream.substring(stream.lastIndexOf('/')+1);
var streamHeader = '!' + stream.substring(stream.lastIndexOf('/')+1, stream.indexOf('.json'));
}
// #tag stream
else if(stream.substring(0,24) == 'statusnet/tags/timeline/') {
var defaultStreamName = stream;
var hashtagString = stream.substring(stream.indexOf('/timeline/')+10,stream.indexOf('.json'));
var streamHeader = '#' + replaceHtmlSpecialChars(decodeURIComponent(hashtagString));
}
// notice stream
else if(stream.substring(0,14) == 'statuses/show/') {
var defaultStreamName = stream;
var streamHeader = 'notice/' + stream.substring(stream.indexOf('/show/')+6,stream.indexOf('.json'));
}
// search stream
else if(stream.substring(0,11) == 'search.json') {
var defaultStreamName = stream;
var streamHeader = window.sL.searchVerb + ': ' + replaceHtmlSpecialChars(decodeURIComponent(stream.substring(stream.indexOf('?q=')+3)));
}
// set the h2 header in the feed
if(stream.substring(0,23) == 'statuses/followers.json') {
var h2FeedHeader = '<div class="queet-streams"><a class="queet-stream following">' + window.sL.following + '</a> / </div>' + window.sL.followers;
}
else if(stream.substring(0,21) == 'statuses/friends.json') {
var h2FeedHeader = window.sL.following + '<div class="queet-streams">/ <a class="queet-stream followers">' + window.sL.followers + '</a></div>';
}
else if(stream.substring(0,40) == 'statuses/user_timeline.json?screen_name=') {
var h2FeedHeader = window.sL.notices + '<div class="queet-streams">/ <a class="queet-stream mentions">' + window.sL.mentions + '</a> / <a class="queet-stream favorites">' + window.sL.favoritesNoun +'</a></div>';
}
else if(stream.substring(0,35) == 'statuses/mentions.json?screen_name=') {
var h2FeedHeader = '<div class="queet-streams"><a class="queet-stream queets">' + window.sL.notices + '</a> /</div>' + window.sL.mentions + '<div class="queet-streams">/ <a class="queet-stream favorites">' + window.sL.favoritesNoun + '</a></div>';
}
else if(stream.substring(0,27) == 'favorites.json?screen_name=') {
var h2FeedHeader = '<div class="queet-streams"><a class="queet-stream queets">' + window.sL.notices + '</a> / <a class="queet-stream mentions">' + window.sL.mentions + '</a> /</div>' + window.sL.favoritesNoun;
}
else if(stream.substring(0,26) == 'statusnet/groups/list.json') {
var h2FeedHeader = window.sL.groups;
}
else if(stream.substring(0,28) == 'statusnet/groups/membership/') {
var h2FeedHeader = window.sL.memberCount;
}
else if(stream.substring(0,24) == 'statusnet/groups/admins/') {
var h2FeedHeader = window.sL.adminCount;
}
else if(stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name=') {
var h2FeedHeader = '<span style="unicode-bidi:bidi-override;direction:ltr;">' + streamHeader + '/all</span>'; // ugly rtl fix, sry, we should have translations for this stream header
if(streamObject.streamSubHeader) {
var h2FeedHeader = streamObject.streamSubHeader;
}
else {
var h2FeedHeader = streamHeader;
var h2FeedHeader = streamObject.streamHeader;
}
// if we have a saved copy of this stream, show it immediately (but it is replaced when stream finishes to load later)
if(typeof window.oldStreams[window.currentStream] != "undefined") {
$('.profile-card,.hoover-card,.hoover-card-caret').remove();
$('.profile-card,.hover-card,.hover-card-caret').remove();
$('#feed').remove();
$('#user-container').after(window.oldStreams[window.currentStream]);
$('.profile-card').css('display','none');
@ -568,14 +541,14 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
$('#feed-header-inner h2').animate({opacity:'1'},1000);
// also mark this stream as the current stream immediately, if a saved copy exists
addStreamToHistoryMenuAndMarkAsCurrent(streamHeader, defaultStreamName);
addStreamToHistoryMenuAndMarkAsCurrent(streamObject);
}
// otherwise we fade out and wait for stream to load
else {
// fade out
$('#feed,.profile-card').animate({opacity:'0'},150,function(){
// when fade out finishes, remove any profile cards and set new header
$('.profile-card,.hoover-card,.hoover-card-caret').remove();
$('.profile-card,.hover-card,.hover-card-caret').remove();
$('#feed-header-inner h2').html(h2FeedHeader);
});
}
@ -588,31 +561,17 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
changeDesign({backgroundimage:window.loggedIn.background_image, backgroundcolor:window.loggedIn.backgroundcolor, linkcolor:window.loggedIn.linkcolor});
}
// for these streams we want a user array in the header to build a profile card
var addUserArray = '';
if(stream.substring(0,23) == 'statuses/followers.json'
|| stream.substring(0,21) == 'statuses/friends.json'
|| stream.substring(0,26) == 'statusnet/groups/list.json'
|| stream.substring(0,35) == 'statuses/mentions.json?screen_name='
|| stream.substring(0,27) == 'favorites.json?screen_name='
|| stream.substring(0,27) == 'statuses/user_timeline.json'
|| stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name=') {
addUserArray = '&withuserarray=1';
}
// get stream
getFromAPI(stream + addUserArray, function(queet_data){
getFromAPI(streamObject.stream, function(queet_data){
if(queet_data) {
// while waiting for this data user might have changed stream, so only proceed if current stream still is this one
if(window.currentStream == stream) {
if(window.currentStream == streamObject.stream) {
// show group profile card if this is a group stream
if(stream.substring(0,26) == 'statusnet/groups/timeline/'
|| stream.substring(0,28) == 'statusnet/groups/membership/'
|| stream.substring(0,24) == 'statusnet/groups/admins/') {
var thisGroupAlias = stream.substring(stream.lastIndexOf('/')+1, stream.indexOf('.json'));
groupProfileCard(thisGroupAlias);
if(streamObject.name == 'group notice stream'
|| streamObject.name == 'group member list'
|| streamObject.name == 'group admin list') {
groupProfileCard(streamObject.nickname);
}
// start checking for new queets again
@ -620,7 +579,7 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
checkForNewQueetsInterval=window.setInterval(function(){checkForNewQueets()},window.timeBetweenPolling);
// add this stream to the history menu
addStreamToHistoryMenuAndMarkAsCurrent(streamHeader, defaultStreamName);
addStreamToHistoryMenuAndMarkAsCurrent(streamObject);
remove_spinner();
$('#feed-body').html(''); // empty feed only now so the scrollers don't flicker on and off
@ -629,29 +588,39 @@ function setNewCurrentStream(stream,actionOnSuccess,setLocation) {
$('#feed').animate({opacity:'1'},150); // fade in
$('body').removeClass('loading-older');$('body').removeClass('loading-newer');
$('html,body').scrollTop(0); // scroll to top
actionOnSuccess(); // return
// maybe do something
if(typeof actionOnSuccess == 'function') {
actionOnSuccess();
}
}
}
});
}
/* ·
·
· Add this stream to history menu if it doesn't exist there (but not if this is me or if we're not logged in)
· and mark this stream as current in menu
· Add this stream to history menu if it doesn't exist in stream selection menus (if we're logged in)
· and mark this stream as current
·
· @param streamHeader: the header to show in the menu
· @param defaultStreamName: the stream to link in the history menu
· @param streamObject: stream object returned by pathToStreamRouter()
·
· · · · · · · · · */
function addStreamToHistoryMenuAndMarkAsCurrent(streamHeader, defaultStreamName) {
function addStreamToHistoryMenuAndMarkAsCurrent(streamObject) {
if($('.stream-selection[data-stream-header="' + streamHeader + '"]').length==0
&& streamHeader != '@' + window.loggedIn.screen_name
if(streamObject.parentPath) {
var urlToMarkAsCurrent = window.siteInstanceURL + streamObject.parentPath;
}
else {
var urlToMarkAsCurrent = window.siteInstanceURL + streamObject.path;
}
if($('.stream-selection[href="' + urlToMarkAsCurrent + '"]').length==0
&& typeof window.loggedIn.screen_name != 'undefined') {
$('#history-container').prepend('<a class="stream-selection" data-stream-header="' + streamHeader + '" href="' + window.siteInstanceURL + convertStreamToPath(defaultStreamName) + '">' + streamHeader + '<i class="chev-right" data-tooltip="' + window.sL.tooltipBookmarkStream + '"></i></a>');
$('#history-container').prepend('<a class="stream-selection" href="' + urlToMarkAsCurrent + '">' + streamObject.streamHeader + '<i class="chev-right" data-tooltip="' + window.sL.tooltipBookmarkStream + '"></i></a>');
updateHistoryLocalStorage();
// max 10 in history container
var historyNum = $('#history-container').children('.stream-selection').length;
@ -662,380 +631,10 @@ function addStreamToHistoryMenuAndMarkAsCurrent(streamHeader, defaultStreamName)
$('.stream-selection').removeClass('current');
$('.stream-selection[data-stream-header="' + streamHeader + '"]').addClass('current');
$('.stream-selection[href="' + urlToMarkAsCurrent + '"]').addClass('current');
}
/* ·
·
· Convert stream to path
·
· @param stream: the stream, e.g. 'public_timeline.json'
· @returns: relative path
·
· · · · · · · · · */
function convertStreamToPath(stream) {
if(stream.substring(0,45) == 'statuses/followers.json?count=20&screen_name=') {
var screenName = stream.substring(stream.lastIndexOf('=')+1);
return screenName + '/subscribers';
}
else if(stream.substring(0,43) == 'statuses/friends.json?count=20&screen_name=') {
var screenName = stream.substring(stream.lastIndexOf('=')+1);
return screenName + '/subscriptions';
}
else if(stream.substring(0,35) == 'statuses/mentions.json?screen_name=') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName + '/replies';
}
else if(stream.substring(0,27) == 'favorites.json?screen_name=') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName + '/favorites';
}
else if(stream.substring(0,48) == 'statusnet/groups/list.json?count=10&screen_name=') {
var screenName = stream.substring(stream.lastIndexOf('=')+1);
return screenName + '/groups';
}
else if(stream == 'statuses/followers.json?count=20') {
return window.loggedIn.screen_name + '/subscribers';
}
else if(stream == 'statuses/friends.json?count=20') {
return window.loggedIn.screen_name + '/subscriptions';
}
else if(stream == 'statuses/mentions.json') {
return window.loggedIn.screen_name + '/replies';
}
else if(stream == 'qvitter/statuses/notifications.json') {
return window.loggedIn.screen_name + '/notifications';
}
else if(stream == 'favorites.json') {
return window.loggedIn.screen_name + '/favorites';
}
else if(stream == 'statusnet/groups/list.json?count=10') {
return window.loggedIn.screen_name + '/groups';
}
else if (stream.substring(0,27) == 'statuses/user_timeline.json') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName;
}
else if(stream == 'statuses/friends_timeline.json') {
return window.loggedIn.screen_name + '/all';
}
else if(stream.substring(0,43) == 'statuses/friends_timeline.json?screen_name=') {
var screenName = stream.substring(stream.indexOf('=')+1);
return screenName + '/all';
}
else if(stream == 'statuses/public_timeline.json') {
return 'main/public';
}
else if(stream == 'statuses/public_and_external_timeline.json') {
return 'main/all';
}
else if(stream.substring(0,26) == 'statusnet/groups/timeline/') {
var groupName = stream.substring(stream.lastIndexOf('/')+1,stream.indexOf('.json'));
return 'group/' + groupName;
}
else if(stream.substring(0,28) == 'statusnet/groups/membership/') {
var groupName = stream.substring(stream.lastIndexOf('/')+1,stream.indexOf('.json'));
return 'group/' + groupName + '/members';
}
else if(stream.substring(0,24) == 'statusnet/groups/admins/') {
var groupName = stream.substring(stream.lastIndexOf('/')+1,stream.indexOf('.json'));
return 'group/' + groupName + '/admins';
}
else if(stream.substring(0,24) == 'statusnet/tags/timeline/') {
var tagName = stream.substring(stream.indexOf('/timeline/')+10,stream.indexOf('.json'));
return 'tag/' + tagName;
}
else if(stream.substring(0,14) == 'statuses/show/') {
var noticeId = stream.substring(stream.indexOf('/show/')+6,stream.indexOf('.json'));
return 'notice/' + noticeId;
}
else if(stream.substring(0,11) == 'search.json') {
var searchTerms = stream.substring(stream.indexOf('?q=')+3);
return 'search/notice?q=' + searchTerms;
}
}
/* ·
·
· Sets the location bar in the browser to correspond with given stream
·
· @param stream: the stream, e.g. 'public_timeline.json'
·
· · · · · · · · · */
function setUrlFromStream(stream) {
history.pushState({strm:stream},'','/' + convertStreamToPath(stream));
}
/* ·
·
· Local URL to stream router
·
· @param url: any URL
·
· · · · · · · · · */
function URLtoStreamRouter(url) {
// structure of the returned object
var streamObject = new Object();
streamObject.nickname = false;
streamObject.id = false;
streamObject.stream = false;
streamObject.name = false;
// we don't expect protocol to matter
url = removeProtocolFromUrl(url);
// remove anchor tags
if(url.indexOf('#')>-1) {
url = url.substring(0,url.indexOf('#'));
}
// not a local URL
if(url != window.siteRootDomain && url.indexOf(window.siteRootDomain + '/') != 0) {
console.log('not a local url: ' + url);
return false;
}
// remove server
var path = url.substring(window.siteRootDomain.length);
// remove starting slash
if(path.indexOf('/') == 0) {
path = path.substring(1);
}
// remove ending slash
if(path.length>0 && path.lastIndexOf('/') == (path.length-1)) {
path = path.substring(0,path.length-1);
}
// front page
if(path.length == 0) {
if(window.siteLocalOnlyDefaultPath) {
streamObject.stream = 'statuses/public_timeline.json';
streamObject.name = 'public timeline';
return streamObject;
}
else {
streamObject.stream = 'statuses/public_and_external_timeline.json';
streamObject.name = 'public and external timeline';
return streamObject;
}
}
// main/all, i.e. full network
if(path == 'main/all') {
streamObject.stream = 'statuses/public_and_external_timeline.json';
streamObject.name = 'public and external timeline';
return streamObject;
}
// main/public, i.e. site's public timeline, new gnu social style
if(path == 'main/public') {
streamObject.stream = 'statuses/public_timeline.json';
streamObject.name = 'public timeline';
return streamObject;
}
// groups directory, qvitter can't handle that yet
if(path == 'groups') {
streamObject.name = 'group directory';
return streamObject;
}
// search/notice?q={urlencoded search terms}
if(path.indexOf('search/notice?q=') == 0) {
var searchQuery = replaceHtmlSpecialChars(loc.replace('/search/notice?q=',''));
if(searchQuery.length>0) {
streamToSet.id = searchQuery;
streamToSet.stream = 'search.json?q=' + searchToStream;
streamObject.name = 'search';
return streamObject;
}
}
// {screen_name}
if(/^[a-zA-Z0-9]+$/.test(path)) {
streamObject.nickname = path;
streamObject.stream = 'statuses/user_timeline.json?screen_name=' + streamObject.nickname;
streamObject.name = 'profile';
return streamObject;
}
var pathSplit = path.split('/');
// tag/{tag}
if(pathSplit.length == 2 && pathSplit[0] == 'tag') {
streamObject.id = pathSplit[1];
streamObject.stream = 'statusnet/tags/timeline/' + streamObject.id + '.json';
streamObject.name = 'tag stream';
return streamObject;
}
// notice/{id}
if(pathSplit.length == 2 && pathSplit[0] == 'notice' && /^[0-9]+$/.test(pathSplit[1])) {
streamObject.id = pathSplit[1];
streamObject.stream = 'statuses/show/' + streamObject.id + '.json';
streamObject.name = 'notice';
return streamObject;
}
// user/{id}
if(pathSplit.length == 2 && pathSplit[0] == 'user' && /^[0-9]+$/.test(pathSplit[1])) {
streamObject.id = pathSplit[1];
streamObject.stream = 'statuses/user_timeline.json?id=' + streamObject.id;
streamObject.name = 'profile';
return streamObject;
}
// group/{group_nickname}
if(pathSplit.length == 2 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1])) {
streamObject.nickname = pathSplit[1];
streamObject.stream = 'statusnet/groups/timeline/' + streamObject.nickname + '.json';
streamObject.name = 'group notice stream';
return streamObject;
}
// group/{group_nickname}/members
if(pathSplit.length == 3 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1]) && pathSplit[2] == 'members') {
streamObject.nickname = pathSplit[1];
streamObject.stream = 'statusnet/groups/membership/' + streamObject.nickname + '.json?count=20';
streamObject.name = 'group member list';
return streamObject;
}
// group/{group_nickname}/admins
if(pathSplit.length == 3 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1]) && pathSplit[2] == 'admins') {
streamObject.nickname = pathSplit[1];
streamObject.stream = 'statusnet/groups/admins/' + streamObject.nickname + '.json?count=20';
streamObject.name = 'group admin list';
return streamObject;
}
// {screen_name}/all
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'all') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/friends_timeline.json';
}
else {
streamObject.stream = 'statuses/friends_timeline.json?screen_name=' + streamObject.nickname;
}
streamObject.name = 'friends timeline';
return streamObject;
}
// {screen_name}/replies
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'replies') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/mentions.json';
}
else {
streamObject.stream = 'statuses/mentions.json?screen_name=' + streamObject.nickname;
}
streamObject.name = 'mentions';
return streamObject;
}
// {screen_name}/notifications
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'notifications') {
streamObject.nickname = pathSplit[0];
// only accessible to the logged in user
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'qvitter/statuses/notifications.json';
}
streamObject.name = 'notifications';
return streamObject;
}
// {screen_name}/favorites
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'favorites') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'favorites.json';
}
else {
streamObject.stream = 'favorites.json?screen_name=' + streamObject.nickname;
}
streamObject.name = 'favorites';
return streamObject;
}
// {screen_name}/subscribers
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'subscribers') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/followers.json?count=20';
}
else {
streamObject.stream = 'statuses/followers.json?count=20&screen_name=' + streamObject.nickname;
}
streamObject.name = 'subscribers';
return streamObject;
}
// {screen_name}/subscriptions
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'subscriptions') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/friends.json?count=20';
}
else {
streamObject.stream = 'statuses/friends.json?count=20&screen_name=' + streamObject.nickname;
}
streamObject.name = 'subscriptions';
return streamObject;
}
// {screen_name}/groups
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'groups') {
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statusnet/groups/list.json?count=10';
}
else {
streamObject.stream = 'statusnet/groups/list.json?count=10&screen_name=' + streamObject.nickname;
}
streamObject.name = 'user group list';
return streamObject;
}
}
/* ·
·
· Get stream from location bar
·
· · · · · · · · · */
function getStreamFromUrl() {
var streamObject = URLtoStreamRouter(window.location.href);
if(streamObject.stream) {
return streamObject.stream;
}
// fallback to friends timeline or public timeline if URLtoStreamRouter can't find a stream
else if(window.loggedIn) {
return 'statuses/friends_timeline.json';
}
else if(window.siteLocalOnlyDefaultPath) {
return 'statuses/public_timeline.json';
}
else {
return 'statuses/public_and_external_timeline.json';
}
}
/* ·
·
@ -2164,10 +1763,10 @@ function buildQueetHtml(obj, idInStream, extraClassesThisRun, requeeted_by, isCo
<a class="account-group" href="' + obj.user.statusnet_profile_url + '">\
<img class="avatar" src="' + obj.user.profile_image_url_profile_size + '" />\
<strong class="name" data-user-id="' + obj.user.id + '">' + obj.user.name + '</strong> \
<span class="screen-name">@' + obj.user.screen_name + '</span>\
</a>\
<i class="addressees">' + reply_to_html + in_groups_html + '</i>\
<small class="created-at" data-created-at="' + obj.created_at + '">\
<span class="screen-name">@' + obj.user.screen_name + '</span>' +
'</a>' +
'<i class="addressees">' + reply_to_html + in_groups_html + '</i>' +
'<small class="created-at" data-created-at="' + obj.created_at + '">\
<a data-tooltip="' + parseTwitterLongDate(obj.created_at) + '" href="' + window.siteInstanceURL + 'notice/' + obj.id + '">' + queetTime + '</a>\
</small>\
</div>\

View File

@ -220,19 +220,19 @@ function checkLocalStorage() {
/* ·
·
· Align tooltips to the hoovered element
· Align tooltips to the hovered element
·
· · · · · · · · · */
function alignTooltipToHooveredElement(tooltipElement,tooltipCaret,hoovered) {
function alignTooltipTohoveredElement(tooltipElement,tooltipCaret,hovered) {
var tooltipWidth = tooltipElement.outerWidth();
var tooltipHeight = tooltipElement.outerHeight();
var windowWidth = $(window).width();
var windowScrollPosY = $(window).scrollTop();
var targetPosX = hoovered.offset().left;
var targetPosY = hoovered.offset().top;
var targetHeight = hoovered.outerHeight();
var targetWidth = hoovered.outerWidth();
var targetPosX = hovered.offset().left;
var targetPosY = hovered.offset().top;
var targetHeight = hovered.outerHeight();
var targetWidth = hovered.outerWidth();
// too little space on top of element, show tooltip at bottom
if((targetPosY-windowScrollPosY-tooltipHeight-10) < 0) {
@ -450,6 +450,19 @@ function userArrayCacheGetByProfileUrlAndNickname(profileUrl, nickname) {
}
}
function userArrayCacheGetUserNicknameById(id) {
var possibleUserURI = window.siteInstanceURL + 'user/' + id;
var key = window.convertUriToUserArrayCacheKey[possibleUserURI];
if(typeof key != 'undefined') {
if(typeof window.userArrayCache[key] != 'undefined') {
return window.userArrayCache[key].local.screen_name;
}
}
return false;
}
/* ·
@ -1142,7 +1155,7 @@ function saveAllBookmarks() {
$.each($('#bookmark-container .stream-selection'), function(key,obj) {
bookmarkContainer[i] = new Object();
bookmarkContainer[i].dataStreamHref = $(obj).attr('href');
bookmarkContainer[i].dataStreamHeader = $(obj).attr('data-stream-header');
bookmarkContainer[i].dataStreamHeader = $(obj).html();
i++;
});
@ -1163,7 +1176,7 @@ function appendAllBookmarks(bookmarkContainer) {
if(bookmarkContainer) {
$('#bookmark-container').html('');
$.each(bookmarkContainer, function(key,obj) {
$('#bookmark-container').append('<a class="stream-selection" data-stream-header="' + obj.dataStreamHeader + '" href="' + obj.dataStreamHref + '">' + obj.dataStreamHeader + '</i><i class="chev-right" data-tooltip="' + window.sL.tooltipRemoveBookmark + '"></i></a>');
$('#bookmark-container').append('<a class="stream-selection" href="' + obj.dataStreamHref + '">' + obj.dataStreamHeader + '</i><i class="chev-right" data-tooltip="' + window.sL.tooltipRemoveBookmark + '"></i></a>');
});
}
$('#bookmark-container').sortable({delay: 100});
@ -1184,7 +1197,7 @@ function updateHistoryLocalStorage() {
$.each($('#history-container .stream-selection'), function(key,obj) {
historyContainer[i] = new Object();
historyContainer[i].dataStreamHref = $(obj).attr('href');
historyContainer[i].dataStreamHeader = $(obj).attr('data-stream-header');
historyContainer[i].dataStreamHeader = $(obj).html();
i++;
});
localStorageObjectCache_STORE('browsingHistory', window.loggedIn.screen_name,historyContainer);
@ -1211,7 +1224,7 @@ function loadHistoryFromLocalStorage() {
$('#history-container').css('display','block');
$('#history-container').html('');
$.each(cacheData, function(key,obj) {
$('#history-container').append('<a class="stream-selection" data-stream-header="' + obj.dataStreamHeader + '" href="' + obj.dataStreamHref + '">' + obj.dataStreamHeader + '</i><i class="chev-right" data-tooltip="' + window.sL.tooltipBookmarkStream + '"></i></a>');
$('#history-container').append('<a class="stream-selection" href="' + obj.dataStreamHref + '">' + obj.dataStreamHeader + '</i><i class="chev-right" data-tooltip="' + window.sL.tooltipBookmarkStream + '"></i></a>');
});
}
updateHistoryLocalStorage();

View File

@ -56,9 +56,9 @@ window.loggedIn = iterateRecursiveReplaceHtmlSpecialChars(window.loggedIn);
window.onpopstate = function(event) {
if(event && event.state) {
display_spinner();
setNewCurrentStream(event.state.strm,function(){
setNewCurrentStream(pathToStreamRouter(event.state.strm),false,function(){
remove_spinner();
},false);
});
}
}
@ -115,8 +115,8 @@ $('body').on({
$('body').prepend(tooltipElement);
$('body').prepend(tooltipCaret);
// align tooltip to the hoovered element
alignTooltipToHooveredElement(tooltipElement,tooltipCaret,$(e.target));
// align tooltip to the hovered element
alignTooltipTohoveredElement(tooltipElement,tooltipCaret,$(e.target));
// fade in
tooltipElement.css('opacity','1');
@ -141,15 +141,22 @@ function removeAllTooltips() {
/* ·
·
· Check for profile hoovercards to display
· Check for profile hovercards to display
·
· · · · · · · · · · · · · */
window.userArrayLastRetrieved = new Object();
$('body').on('mouseover',function (e) {
// no hovercards on these elements
if($(e.target).is('#user-queets') || $(e.target).closest('a').is('#user-queets')
|| $(e.target).is('.tweet-stats') || $(e.target).closest('a').is('.tweet-stats')) {
return true;
}
var timeNow = new Date().getTime();
removeAllHooverCards(e,timeNow);
var hooverCardData = false;
removeAllhoverCards(e,timeNow);
var hoverCardData = false;
var userArray = false;
var hrefAttr = false;
var possibleNickname = false;
@ -211,20 +218,20 @@ $('body').on('mouseover',function (e) {
return;
}
var hooverCardElement = $('<div id="hoover-card-' + timeNow + '" class="hoover-card" data-card-created="' + timeNow + '">' + profileCard.profileCardHtml + '</div>');
var hooverCardCaret = $('<div id="hoover-card-caret-' + timeNow + '" class="hoover-card-caret"></div>');
var hoverCardElement = $('<div id="hover-card-' + timeNow + '" class="hover-card" data-card-created="' + timeNow + '">' + profileCard.profileCardHtml + '</div>');
var hoverCardCaret = $('<div id="hover-card-caret-' + timeNow + '" class="hover-card-caret"></div>');
targetElement.attr('data-awaiting-hoover-card',timeNow);
targetElement.attr('data-awaiting-hover-card',timeNow);
// let user hoover for 600ms before showing the card
// let user hover for 600ms before showing the card
setTimeout(function(){
// make sure user is still hoovering the same link and that that the link awaits the same hoover card
// (user can have flickered on and off the link triggering two or more hoover cards to in setTimeout delay)
if(targetElement.is(":hover") && parseInt(targetElement.attr('data-awaiting-hoover-card'),10) == timeNow) {
if($('.hoover-card').length == 0) { // no card if there already is one open
$('body').prepend(hooverCardElement);
$('body').prepend(hooverCardCaret);
targetElement.attr('data-hoover-card-active',timeNow);
// make sure user is still hovering the same link and that that the link awaits the same hover card
// (user can have flickered on and off the link triggering two or more hover cards to in setTimeout delay)
if(targetElement.is(":hover") && parseInt(targetElement.attr('data-awaiting-hover-card'),10) == timeNow) {
if($('.hover-card').length == 0) { // no card if there already is one open
$('body').prepend(hoverCardElement);
$('body').prepend(hoverCardCaret);
targetElement.attr('data-hover-card-active',timeNow);
// if the user array has not been retrieved from the server for the last 60 seconds,
// we query it for the lastest data
@ -236,8 +243,8 @@ $('body').on('mouseover',function (e) {
getFromAPI('users/show.json?id=' + userArray.local.screen_name, function(data){
if(data) {
var newProfileCard = buildProfileCard(data);
hooverCardElement.html(newProfileCard.profileCardHtml);
alignTooltipToHooveredElement(hooverCardElement,hooverCardCaret,targetElement);
hoverCardElement.html(newProfileCard.profileCardHtml);
alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
}
});
}
@ -247,8 +254,8 @@ $('body').on('mouseover',function (e) {
getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(userArray.local.statusnet_profile_url),function(data){
if(data && data.external !== null) {
var newProfileCard = buildExternalProfileCard(data);
hooverCardElement.html(newProfileCard.profileCardHtml);
alignTooltipToHooveredElement(hooverCardElement,hooverCardCaret,targetElement);
hoverCardElement.html(newProfileCard.profileCardHtml);
alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
}
});
}
@ -257,12 +264,12 @@ $('body').on('mouseover',function (e) {
// hide tooltips
$('.tooltip,.tooltip-caret').remove();
// align hoover card to the hoovered element
alignTooltipToHooveredElement(hooverCardElement,hooverCardCaret,targetElement);
// align hover card to the hovered element
alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
// fade in
hooverCardElement.css('opacity','1');
hooverCardCaret.css('opacity','1');
hoverCardElement.css('opacity','1');
hoverCardCaret.css('opacity','1');
}
}
},timeOut);
@ -295,7 +302,7 @@ function getUserArrayData(maybeProfileUrl,maybeNickname,timeNow,callback) {
if(data) {
userArray = {local:data};
// we want hoover cards to appear _at least_ 600ms after hoover
// we want hover cards to appear _at least_ 600ms after hover
// we could just set the timeout to 0 and let the card appear
// whenever it's loaded, but this will not feel good if we're
// on a crazy fast server. so we calculate the diff time and makes
@ -309,7 +316,7 @@ function getUserArrayData(maybeProfileUrl,maybeNickname,timeNow,callback) {
var timeOut = 0;
}
// continue to display the hoover card
// continue to display the hover card
callback(userArray,timeOut);
}
});
@ -318,7 +325,7 @@ function getUserArrayData(maybeProfileUrl,maybeNickname,timeNow,callback) {
}
// from cache
else {
// continue to display the hoover card
// continue to display the hover card
// 600ms before cards appear feels pretty good
// but this can be tweaked if cards appear to fast/slow
callback(userArray,600);
@ -326,23 +333,23 @@ function getUserArrayData(maybeProfileUrl,maybeNickname,timeNow,callback) {
}
}
// hoover cards should be removed very easily, e.g. when any of these events happen
// hover cards should be removed very easily, e.g. when any of these events happen
$('body').on("mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup", function(e){
var timeNow = new Date().getTime();
removeAllHooverCards(e,timeNow);
removeAllhoverCards(e,timeNow);
});
// removes all hover cards
function removeAllHooverCards(event,priorTo) {
function removeAllhoverCards(event,priorTo) {
// don't remove hovercards until after 100ms, so user have time to move the cursor to it (which gives it the dont-remove-card class)
setTimeout(function(){
$.each($('.hoover-card'),function(){
// don't remove card if it was created after removeAllHooverCards() was called
$.each($('.hover-card'),function(){
// don't remove card if it was created after removeAllhoverCards() was called
if($(this).data('card-created') < priorTo) {
// don't remove it if we're hoovering it right now!
// don't remove it if we're hovering it right now!
if(!$(this).hasClass('dont-remove-card')) {
$('[data-hoover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hoover-card-active');
$('#hoover-card-caret-' + $(this).data('card-created')).remove();
$('[data-hover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hover-card-active');
$('#hover-card-caret-' + $(this).data('card-created')).remove();
$(this).remove();
}
}
@ -350,11 +357,11 @@ function removeAllHooverCards(event,priorTo) {
},100);
}
// if we're hoovering a hoover card, give it a class, so we don't remove it
$('body').on('mouseover','.hoover-card', function(e) {
// if we're hovering a hover card, give it a class, so we don't remove it
$('body').on('mouseover','.hover-card', function(e) {
$(this).addClass('dont-remove-card');
});
$('body').on('mouseleave','.hoover-card', function(e) {
$('body').on('mouseleave','.hover-card', function(e) {
$(this).removeClass('dont-remove-card');
});
@ -700,6 +707,7 @@ function proceedToSetLanguageAndLogin(data){
$('.front-welcome-text').append(window.sL.welcomeText);
}
}
$('#nickname').attr('placeholder',window.sL.loginUsername);
$('#password').attr('placeholder',window.sL.loginPassword);
$('button#submit-login').html(window.sL.loginSignIn);
@ -723,18 +731,12 @@ function proceedToSetLanguageAndLogin(data){
$('#other-servers-link').html(window.sL.otherServers);
$('.language-dropdown .dropdown-toggle small').html(window.sL.languageSelected);
$('.language-dropdown .current-language').html(window.sL.languageName);
$('.stream-selection[data-stream-name="statuses/friends_timeline.json"]').prepend(window.sL.timeline);
$('.stream-selection[data-stream-name="statuses/friends_timeline.json"]').attr('data-stream-header',window.sL.timeline);
$('.stream-selection[data-stream-name="statuses/mentions.json"]').prepend(window.sL.mentions);
$('.stream-selection[data-stream-name="statuses/mentions.json"]').attr('data-stream-header',window.sL.mentions);
$('.stream-selection[data-stream-name="qvitter/statuses/notifications.json"]').prepend(window.sL.notifications);
$('.stream-selection[data-stream-name="qvitter/statuses/notifications.json"]').attr('data-stream-header',window.sL.notifications);
$('.stream-selection[data-stream-name="favorites.json"]').prepend(window.sL.favoritesNoun);
$('.stream-selection[data-stream-name="favorites.json"]').attr('data-stream-header',window.sL.favoritesNoun);
$('.stream-selection[data-stream-name="statuses/public_timeline.json"]').prepend(window.sL.publicTimeline);
$('.stream-selection[data-stream-name="statuses/public_timeline.json"]').attr('data-stream-header',window.sL.publicTimeline);
$('.stream-selection[data-stream-name="statuses/public_and_external_timeline.json"]').prepend(window.sL.publicAndExtTimeline);
$('.stream-selection[data-stream-name="statuses/public_and_external_timeline.json"]').attr('data-stream-header',window.sL.publicAndExtTimeline);
$('.stream-selection.friends-timeline').prepend(window.sL.timeline);
$('.stream-selection.mentions').prepend(window.sL.mentions);
$('.stream-selection.notifications').prepend(window.sL.notifications);
$('.stream-selection.favorites').prepend(window.sL.favoritesNoun);
$('.stream-selection.public-timeline').prepend(window.sL.publicTimeline);
$('.stream-selection.public-and-external-timeline').prepend(window.sL.publicAndExtTimeline)
$('#search-query').attr('placeholder',window.sL.searchVerb);
$('#faq-link').html(window.sL.FAQ);
$('#shortcuts-link').html(window.sL.keyboardShortcuts);
@ -750,6 +752,7 @@ function proceedToSetLanguageAndLogin(data){
$('.reload-stream').attr('data-tooltip',window.sL.tooltipReloadStream);
$('#clear-history').html(window.sL.clearHistory);
// show site body now
$('#user-container').css('display','block');
$('#feed').css('display','block');
@ -761,10 +764,10 @@ function proceedToSetLanguageAndLogin(data){
else {
display_spinner();
window.currentStream = ''; // force reload stream
setNewCurrentStream(getStreamFromUrl(),function(){
setNewCurrentStream(getStreamFromUrl(),true,function(){
logoutWithoutReload(false);
remove_spinner();
},true);
});
}
}
@ -784,7 +787,7 @@ $('#form_login').submit(function(e) {
}
});
function doLogin(streamToSet) {
function doLogin(streamObjectToSet) {
$('#submit-login').attr('disabled','disabled');
$('#submit-login').focus(); // prevents submit on enter to close alert-popup on wrong credentials
display_spinner();
@ -807,6 +810,9 @@ function doLogin(streamToSet) {
$('.stream-selection.notifications').attr('href', window.loggedIn.statusnet_profile_url + '/notifications');
$('.stream-selection.my-timeline').attr('href', window.loggedIn.statusnet_profile_url);
$('.stream-selection.favorites').attr('href', window.loggedIn.statusnet_profile_url + '/favorites');
$('#user-queets').attr('href',window.loggedIn.statusnet_profile_url);
$('#user-following').attr('href',window.loggedIn.statusnet_profile_url + '/subscriptions');
$('#user-groups').attr('href',window.loggedIn.statusnet_profile_url + '/groups');
window.myUserID = window.loggedIn.id;
if(window.loggedIn.cover_photo !== false) {
$('#user-header').css('background-image','url(\'' + window.loggedIn.cover_photo + '\')');
@ -876,7 +882,7 @@ function doLogin(streamToSet) {
// set stream
window.currentStream = ''; // always reload stream on login
setNewCurrentStream(streamToSet,function(){
setNewCurrentStream(streamObjectToSet,true,function(){
$('.language-dropdown').css('display','none');
$('#user-header').animate({opacity:'1'},800);
$('#user-body').animate({opacity:'1'},800);
@ -890,7 +896,7 @@ function doLogin(streamToSet) {
$('#top-compose').fadeIn('slow');
$('input#nickname').blur();
remove_spinner();
},true);
});
}
@ -1189,76 +1195,19 @@ $('body').on('click','.member-button',function(event){
/* ·
·
· Select a stream when the logged in user clicks their own queets, followers etc
· Go to profile page when clicking the small user header in left column
·
· · · · · · · · · · · · · */
$('#user-header, #user-queets, #user-following, #user-followers, #user-groups').on('click',function(e){
$('#user-header').on('click',function(e){
// not if we're clicking the mini-edit-profile-button
if($(e.target).is('#mini-edit-profile-button')) {
return;
}
if($(this).attr('id') == 'user-header' || $(this).attr('id') == 'user-queets') {
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name,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);
}
setNewCurrentStream(pathToStreamRouter(window.loggedIn.screen_name),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('following')) {
setNewCurrentStream('statuses/friends.json?count=20',function(){},true);
}
else if($(this).hasClass('followers')) {
setNewCurrentStream('statuses/followers.json?count=20',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);
}
});
/* ·
·
@ -1269,8 +1218,8 @@ $('body').on('click','.profile-banner-footer .stats li a, .queet-stream',functio
$('#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(replaceHtmlSpecialChars($('#search-query').val()));
setNewCurrentStream(streamName,function(){},true);
var path = 'search/notice?q=' + encodeURIComponent(replaceHtmlSpecialChars($('#search-query').val()));
setNewCurrentStream(pathToStreamRouter(path),true);
}
@ -1309,104 +1258,50 @@ $('body').on('click','a', function(e) {
// all links opens in new tab
$(this).attr('target','_blank');
if(typeof $(this).attr('href') != 'undefined') {
// only proceed if we really have a href attribute
if(typeof $(this).attr('href') == 'undefined') {
return;
}
// site root
if($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain,'') == '/') {
// profile picture
if ($(this).hasClass('profile-picture')) {
e.preventDefault();
if($(this).closest('.modal-container').attr('id') != 'edit-profile-popup') { // no popup if we're editing our profile
popUpAction('popup-profile-picture', $('.profile-card-inner .screen-name').html(),'<img style="width:100%;display:block;" src="' + $(this).attr('href') + '" />',false);
}
}
// hijack link if we find a matching link that qvitter can handle
else {
var streamObject = URLtoStreamRouter($(this).attr('href'));
if(streamObject && streamObject.stream) {
e.preventDefault();
setNewCurrentStream('statuses/public_timeline.json',function(){},true);
}
// site root new gnu social style
else if($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain,'') == '/main/public') {
e.preventDefault();
setNewCurrentStream('statuses/public_timeline.json',function(){},true);
}
// whole network feed
else if($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain,'') == '/main/all') {
e.preventDefault();
setNewCurrentStream('statuses/public_and_external_timeline.json',function(){},true);
}
// logged in users streams
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/all') {
e.preventDefault();
setNewCurrentStream('statuses/friends_timeline.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/replies') {
e.preventDefault();
setNewCurrentStream('statuses/mentions.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/notifications') {
e.preventDefault();
setNewCurrentStream('qvitter/statuses/notifications.json',function(){},true);
}
else if ($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/' + window.loggedIn.screen_name,'') == '/favorites') {
e.preventDefault();
setNewCurrentStream('favorites.json',function(){},true);
}
// profiles
else if ((/^[a-zA-Z0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/','')))
|| (/^[0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/user/','')))) {
if($(this).attr('href').indexOf('/user/') > -1) {
var linkNickname = $(this).text().toLowerCase();
if(linkNickname.substring(0,1) == '@') {
linkNickname = linkNickname.substring(1);
// if this is a user/{id} type link
if(streamObject.name == 'profile by id') {
// see if we have the nickname in cache
var nickname = userArrayCacheGetUserNicknameById(streamObject.id);
if(nickname) {
setNewCurrentStream(pathToStreamRouter(nickname),true);
}
// if we don't have it in cache we query the server for it
// (we _could_ just try the nickname in the link html, but the user can have changed nickname)
else {
display_spinner();
getUserIdFromNicknameFromAPI(streamObject.id,function(nickname) {
if(nickname) {
setNewCurrentStream(pathToStreamRouter(nickname),true);
}
else {
remove_spinner();
alert('could not find local user with id ' + streamObject.id);
}
});
}
}
else {
var linkNickname = $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/','');
setNewCurrentStream(streamObject,true);
}
// don't hijack /groups-url
if(linkNickname == 'groups') {
return;
}
e.preventDefault();
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + linkNickname,function(){},true);
}
// tags
else if ($(this).attr('href').indexOf(window.siteRootDomain + '/tag/')>-1) {
e.preventDefault();
setNewCurrentStream('statusnet/tags/timeline/' + $(this).text().toLowerCase().replace('#','') + '.json',function(){},true);
}
// notices
else if ($(this).attr('href').indexOf(window.siteRootDomain + '/notice/')>-1 && $(this).attr('href').indexOf(window.siteRootDomain + '/notice/delete/')==-1) {
e.preventDefault();
setNewCurrentStream('statuses/show/' + $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/notice/','') + '.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();
if(groupName.substring(0,1) == '!') {
groupName = groupName.substring(1);
}
}
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);
}
// search
else if ($(this).attr('href').indexOf('/search/notice?q=')>-1) {
e.preventDefault();
var searchToStream = $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain,'').replace('/search/notice?q=','');
setNewCurrentStream('search.json?q=' + searchToStream,function(){},true);
}
// profile picture
else if ($(this).hasClass('profile-picture')) {
e.preventDefault();
if($(this).closest('.modal-container').attr('id') != 'edit-profile-popup') { // no popup if we're editing our profile
popUpAction('popup-profile-picture', $('.profile-card-inner .screen-name').html(),'<img style="width:100%;display:block;" src="' + $(this).attr('href') + '" />',false);
}
}
}
});
@ -1523,7 +1418,7 @@ $(window).scroll(function() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 1000) {
// not if we're already loading or if no stream is set yet
if(!$('body').hasClass('loading-older') && typeof window.currentStream != "undefined") {
if(!$('body').hasClass('loading-older') && typeof window.currentStream != "undefined" && $('#feed-body').attr('data-end-reached') != 'true') {
$('body').addClass('loading-older');
// remove loading class in 10 seconds, i.e. try again if failed to load within 10 s
@ -1533,13 +1428,9 @@ $(window).scroll(function() {
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 this is a stream that uses 'page' for paging, i.e. search or users lists,
// we need page and rpp vars (page number is stored in an attribute in feed-body)
if(window.currentStreamObject.maxIdOrPage == 'page') {
if(typeof $('#feed-body').attr('data-search-page-number') != 'undefined') {
var searchPage = parseInt($('#feed-body').attr('data-search-page-number'),10);
}
@ -1547,7 +1438,7 @@ $(window).scroll(function() {
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
var getVars = qOrAmp(window.currentStream) + 'rpp=20&page=' + searchPage; // search uses 'rpp' var and others 'count' for paging, though we can add rrp to others aswell without any problem
}
// normal streams
else {
@ -1556,22 +1447,23 @@ $(window).scroll(function() {
display_spinner('#footer-spinner-container');
getFromAPI(window.currentStream + getVars,function(data){
if(data) {
// if data returned an empty array, we have probably reached the bottom
if(data.length == 0) {
$('#feed-body').attr('data-end-reached',true);
}
else 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/') {
// if this is search our group users lists, we remember page number (if we got any users)
if(window.currentStreamObject.maxIdOrPage == 'page') {
$('#feed-body').attr('data-search-page-number',nextPage);
}
remove_spinner();
}
remove_spinner();
});
}
}
@ -1625,7 +1517,7 @@ function checkForNewQueets() {
if(new_queets_num > 0) {
// if this is notifications page, update site title with hidden notification count
if(window.currentStream == 'qvitter/statuses/notifications.json') {
if(window.currentStreamObject.name == 'notifications') {
document.title = window.siteTitle + ' (' + new_queets_num + ')';
}
@ -1652,7 +1544,7 @@ function checkForNewQueets() {
· · · · · · · · · · · · · */
$('body').on('click','#new-queets-bar',function(){
if(window.currentStream == 'qvitter/statuses/notifications.json') {
if(window.currentStreamObject.name == 'notifications') {
document.title = window.siteTitle;
}
var hiddenStreamItems = $('.stream-item.hidden');
@ -2303,10 +2195,10 @@ $('body').on('click', '.queet-toolbar button',function () {
}
// if we can't find a proper place, add it to top and remove conversation class
// if this is either 1) our home/all feed, 2) our user timeline or 3) whole site or 4) whole network
else if(window.currentStream.indexOf('statuses/friends_timeline.json') > -1
|| window.currentStream.indexOf('statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name) > -1
|| window.currentStream.indexOf('statuses/public_timeline.json') > -1
|| window.currentStream.indexOf('statuses/public_and_external_timeline.json') > -1 ) {
else if(window.currentStreamObject.name == 'friends timeline'
|| window.currentStreamObject.name == 'my profile'
|| window.currentStreamObject.name == 'public timeline'
|| window.currentStreamObject.name == 'public and external timeline') {
$('#feed-body').prepend(queetHtml.replace('class="stream-item conversation','class="stream-item'));
}
// don't add it to the current stream, open a popup instead, without conversation class
@ -2411,9 +2303,9 @@ $('body').on('click','button.shorten',function () {
· · · · · · · · · · · · · */
$('body').on('click','.reload-stream',function () {
$('.reload-stream').hide();
setNewCurrentStream(window.currentStream,function(){
setNewCurrentStream(URLtoStreamRouter(window.location.href),false,function(){
$('.reload-stream').show();
},false);
});
});
@ -3036,7 +2928,7 @@ $('body').on('click','#page-container > .profile-card .edit-profile-button',func
if(data.cover_photo !== false) {
coverPhotoHtml = 'background-image:url(\'' + data.cover_photo + '\')';
}
$('.hoover-card,.hoover-card-caret').remove();
$('.hover-card,.hover-card-caret').remove();
$('#edit-profile-popup').prepend('\
<div class="edit-profile-container">\
<div class="upload-background-image"></div>\
@ -3607,13 +3499,13 @@ function uploadImage(e, thisUploadButton) {
·
· · · · · · · · · · · · · */
$('body').on('click','#mini-edit-profile-button, #edit-profile-header-link, .hoover-card .edit-profile-button',function(){
if(window.currentStream == 'statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name) {
$('body').on('click','#mini-edit-profile-button, #edit-profile-header-link, .hover-card .edit-profile-button',function(){
if(window.currentStreamObject.name == 'my profile') {
$('#page-container > .profile-card .edit-profile-button').trigger('click');
}
else {
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name, function(){
setNewCurrentStream(pathToStreamRouter(window.loggedIn.screen_name), true, function(){
$('#page-container > .profile-card .edit-profile-button').trigger('click');
},true);
});
}
});

370
js/stream-router.js Normal file
View File

@ -0,0 +1,370 @@
/*· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
· ·
· <o) ·
· /_//// ·
· (____/ ·
· (o< ·
· o> \\\\_\ ·
· \\) \____) ·
· ·
· ·
· @licstart The following is the entire license notice for the ·
· JavaScript code in this page. ·
· ·
· Copyright (C) 2015 Hannes Mannerheim and other contributors ·
· ·
· ·
· This program 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 3 of the ·
· License, or (at your option) any later version. ·
· ·
· This program is distributed in the hope that it will be useful, ·
· but WITHOUT ANY WARRANTY; without even the implied warranty of ·
· MERCHANTABILITY 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 this program. If not, see <http://www.gnu.org/licenses/>. ·
· ·
· @licend The above is the entire license notice ·
· for the JavaScript code in this page. ·
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
/* ·
·
· Sets the location bar in the browser to correspond with given stream
·
· @param streamObject: stream object returned by pathToStreamRouter
·
· · · · · · · · · */
function setUrlFromStream(streamObject) {
history.pushState({strm:streamObject.path},'','/' + streamObject.path);
}
/* ·
·
· Local URL to stream router
·
· @param url: any URL
·
· · · · · · · · · */
function URLtoStreamRouter(url) {
// we don't expect protocol to matter
url = removeProtocolFromUrl(url);
// remove anchor tags
if(url.indexOf('#')>-1) {
url = url.substring(0,url.indexOf('#'));
}
// not a local URL
if(url != window.siteRootDomain && url.indexOf(window.siteRootDomain + '/') != 0) {
// console.log('not a local url: ' + url);
return false;
}
// remove server
var path = url.substring(window.siteRootDomain.length);
return pathToStreamRouter(path);
}
/* ·
·
· Path to stream router
·
· @param path: path, with or without starting slash
·
· · · · · · · · · */
function pathToStreamRouter(path) {
// remove starting slash
if(path.indexOf('/') == 0) {
path = path.substring(1);
}
// remove ending slash
if(path.length>0 && path.lastIndexOf('/') == (path.length-1)) {
path = path.substring(0,path.length-1);
}
// if we're on the instance base url and logged in, route to {nickname}/all
if(window.loggedIn && path.length == 0) {
path = window.loggedIn.screen_name + '/all';
}
// structure of the returned object
var streamObject = {
path: path, // this path
name: false, // human readable name
streamHeader: false, // short header, e.g. links and buttons no html!
streamSubHeader: false, // a longer header, that can include html and links
parentPath: false, // a parent path can e.g. be "group/qvitter" for "group/qvitter/members"
stream: false, // the API path
nickname: false, // if we can read a nickname/screen_name from the path, add it to this property
id: false, // if we can read a id number string from the path, add it to this property
maxIdOrPage: 'maxId' // whether this stream uses 'maxId' or 'page' for paging (maxId is default)
};
// instance's public timeline
if((path.length == 0 && window.siteLocalOnlyDefaultPath) || path == 'main/public') {
streamObject.path = 'main/public';
streamObject.name = 'public timeline';
streamObject.streamHeader = window.sL.timeline;
streamObject.stream = 'statuses/public_timeline.json';
return streamObject;
}
// the whole known network
if(path.length == 0 || path == 'main/all') {
streamObject.path = 'main/all';
streamObject.name = 'public and external timeline';
streamObject.streamHeader = window.sL.publicAndExtTimeline;
streamObject.stream = 'statuses/public_and_external_timeline.json';
return streamObject;
}
// groups directory, qvitter can't handle that yet
if(path == 'groups') {
streamObject.name = 'group directory';
return streamObject;
}
// search/notice?q={urlencoded search terms}
if(path.indexOf('search/notice?q=') == 0) {
var searchQuery = replaceHtmlSpecialChars(path.replace('search/notice?q=',''));
if(searchQuery.length>0) {
streamObject.name = 'search';
streamObject.streamHeader = window.sL.searchVerb + ': ' + replaceHtmlSpecialChars(decodeURIComponent(searchQuery));
streamObject.stream = 'search.json?q=' + searchQuery;
streamObject.id = searchQuery;
streamObject.maxIdOrPage = 'page';
return streamObject;
}
}
// {screen_name}
if(/^[a-zA-Z0-9]+$/.test(path)) {
streamObject.name = 'profile';
if(window.loggedIn.screen_name == path) {
streamObject.name = 'my profile';
}
streamObject.nickname = path;
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = window.sL.notices + '<div class="queet-streams">/ <a class="queet-stream mentions" href="' + window.siteInstanceURL + streamObject.nickname + '/replies">' + window.sL.mentions + '</a> / <a class="queet-stream favorites" href="' + window.siteInstanceURL + streamObject.nickname + '/favorites">' + window.sL.favoritesNoun +'</a></div>';
streamObject.stream = 'statuses/user_timeline.json?screen_name=' + streamObject.nickname + '&withuserarray=1';
return streamObject;
}
var pathSplit = path.split('/');
// tag/{tag}
if(pathSplit.length == 2 && pathSplit[0] == 'tag') {
streamObject.name = 'tag stream';
streamObject.streamHeader = '#' + replaceHtmlSpecialChars(pathSplit[1]);
streamObject.id = pathSplit[1];
streamObject.stream = 'statusnet/tags/timeline/' + streamObject.id + '.json';
return streamObject;
}
// notice/{id}
if(pathSplit.length == 2 && pathSplit[0] == 'notice' && /^[0-9]+$/.test(pathSplit[1])) {
streamObject.name = 'notice';
streamObject.streamHeader = replaceHtmlSpecialChars(path);
streamObject.id = pathSplit[1];
streamObject.stream = 'statuses/show/' + streamObject.id + '.json';
return streamObject;
}
// user/{id}
if(pathSplit.length == 2 && pathSplit[0] == 'user' && /^[0-9]+$/.test(pathSplit[1])) {
streamObject.name = 'profile by id';
streamObject.nickname = userArrayCacheGetUserNicknameById(pathSplit[1]);
if(streamObject.nickname === false) {
streamObject.streamHeader = replaceHtmlSpecialChars(path);
}
else {
streamObject.streamHeader = '@' + streamObject.nickname;
streamObject.parentPath = streamObject.nickname;
streamObject.streamSubHeader = window.sL.notices + '<div class="queet-streams">/ <a class="queet-stream mentions" href="' + window.siteInstanceURL + streamObject.nickname + '/replies">' + window.sL.mentions + '</a> / <a class="queet-stream favorites" href="' + window.siteInstanceURL + streamObject.nickname + '/favorites">' + window.sL.favoritesNoun +'</a></div>';
}
streamObject.id = pathSplit[1];
streamObject.stream = 'statuses/user_timeline.json?id=' + streamObject.id + '&withuserarray=1';
return streamObject;
}
// group/{group_nickname}
if(pathSplit.length == 2 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1])) {
streamObject.name = 'group notice stream';
streamObject.nickname = pathSplit[1];
streamObject.streamHeader = '!' + replaceHtmlSpecialChars(pathSplit[1]);
streamObject.stream = 'statusnet/groups/timeline/' + streamObject.nickname + '.json';
return streamObject;
}
// group/{group_nickname}/members
if(pathSplit.length == 3 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1]) && pathSplit[2] == 'members') {
streamObject.name = 'group member list';
streamObject.nickname = pathSplit[1];
streamObject.parentPath = 'group/' + streamObject.nickname;
streamObject.streamHeader = '!' + replaceHtmlSpecialChars(pathSplit[1]);
streamObject.streamSubHeader = window.sL.memberCount;
streamObject.stream = 'statusnet/groups/membership/' + streamObject.nickname + '.json?count=20';
streamObject.maxIdOrPage = 'page';
return streamObject;
}
// group/{group_nickname}/admins
if(pathSplit.length == 3 && pathSplit[0] == 'group' && /^[a-zA-Z0-9]+$/.test(pathSplit[1]) && pathSplit[2] == 'admins') {
streamObject.name = 'group admin list';
streamObject.nickname = pathSplit[1];
streamObject.parentPath = 'group/' + streamObject.nickname;
streamObject.streamHeader = '!' + replaceHtmlSpecialChars(pathSplit[1]);
streamObject.streamSubHeader = window.sL.adminCount;
streamObject.stream = 'statusnet/groups/admins/' + streamObject.nickname + '.json?count=20';
streamObject.maxIdOrPage = 'page';
return streamObject;
}
// {screen_name}/all
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'all') {
streamObject.name = 'friends timeline';
streamObject.nickname = pathSplit[0];
streamObject.streamHeader = replaceHtmlSpecialChars(path);
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/friends_timeline.json';
streamObject.streamSubHeader = window.sL.timeline;
}
else {
streamObject.stream = 'statuses/friends_timeline.json?screen_name=' + streamObject.nickname + '&withuserarray=1';
streamObject.parentPath = streamObject.nickname;
}
return streamObject;
}
// {screen_name}/replies
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'replies') {
streamObject.name = 'mentions';
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'statuses/mentions.json';
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = window.sL.mentions;
}
else {
streamObject.parentPath = streamObject.nickname;
streamObject.stream = 'statuses/mentions.json?screen_name=' + streamObject.nickname + '&withuserarray=1';
streamObject.streamSubHeader = '<div class="queet-streams"><a class="queet-stream queets" href="' + window.siteInstanceURL + streamObject.nickname + '">' + window.sL.notices + '</a> /</div>' + window.sL.mentions + '<div class="queet-streams">/ <a class="queet-stream favorites" href="' + window.siteInstanceURL + streamObject.nickname + '/favorites">' + window.sL.favoritesNoun + '</a></div>';
}
return streamObject;
}
// {screen_name}/notifications
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'notifications') {
streamObject.name = 'notifications';
streamObject.nickname = pathSplit[0];
// only accessible to the logged in user
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'qvitter/statuses/notifications.json';
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = window.sL.notifications;
}
return streamObject;
}
// {screen_name}/favorites
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'favorites') {
streamObject.name = 'favorites';
streamObject.nickname = pathSplit[0];
if(window.loggedIn.screen_name == streamObject.nickname) {
streamObject.stream = 'favorites.json';
streamObject.streamSubHeader = window.sL.favoritesNoun;
}
else {
streamObject.parentPath = streamObject.nickname;
streamObject.stream = 'favorites.json?screen_name=' + streamObject.nickname + '&withuserarray=1';
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = '<div class="queet-streams"><a class="queet-stream queets" href="' + window.siteInstanceURL + streamObject.nickname + '">' + window.sL.notices + '</a> / <a class="queet-stream mentions" href="' + window.siteInstanceURL + streamObject.nickname + '/replies">' + window.sL.mentions + '</a> /</div>' + window.sL.favoritesNoun;
}
return streamObject;
}
// {screen_name}/subscribers
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'subscribers') {
streamObject.name = 'subscribers';
streamObject.nickname = pathSplit[0];
streamObject.parentPath = streamObject.nickname;
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = '<div class="queet-streams"><a class="queet-stream following" href="' + window.siteInstanceURL + streamObject.nickname + '/subscriptions">' + window.sL.following + '</a> / </div>' + window.sL.followers;
streamObject.stream = 'statuses/followers.json?count=20&screen_name=' + streamObject.nickname + '&withuserarray=1';
streamObject.maxIdOrPage = 'page';
return streamObject;
}
// {screen_name}/subscriptions
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'subscriptions') {
streamObject.name = 'subscriptions';
streamObject.nickname = pathSplit[0];
streamObject.parentPath = streamObject.nickname;
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = window.sL.following + '<div class="queet-streams">/ <a class="queet-stream followers" href="' + window.siteInstanceURL + streamObject.nickname + '/subscribers">' + window.sL.followers + '</a></div>';
streamObject.stream = 'statuses/friends.json?count=20&screen_name=' + streamObject.nickname + '&withuserarray=1';
streamObject.maxIdOrPage = 'page';
return streamObject;
}
// {screen_name}/groups
if(pathSplit.length == 2 && /^[a-zA-Z0-9]+$/.test(pathSplit[0]) && pathSplit[1] == 'groups') {
streamObject.name = 'user group list';
streamObject.nickname = pathSplit[0];
streamObject.parentPath = streamObject.nickname;
streamObject.streamHeader = '@' + replaceHtmlSpecialChars(streamObject.nickname);
streamObject.streamSubHeader = window.sL.groups;
streamObject.stream = 'statusnet/groups/list.json?count=10&screen_name=' + streamObject.nickname + '&withuserarray=1';
return streamObject;
}
}
/* ·
·
· Get stream from location bar
·
· · · · · · · · · */
function getStreamFromUrl() {
var streamObject = URLtoStreamRouter(window.location.href);
if(streamObject.stream) {
return streamObject;
}
// fallback to friends timeline or public timeline if URLtoStreamRouter can't find a stream
else if(window.loggedIn) {
return pathToStreamRouter(window.loggedIn.screen_name + '/all');
}
else if(window.siteLocalOnlyDefaultPath) {
return pathToStreamRouter('main/public');
}
else {
return pathToStreamRouter('main/all');
}
}