caching of profile cards in window object. also: open popups for local users
This commit is contained in:
parent
a017ad1940
commit
d749713ef3
|
@ -1858,22 +1858,30 @@ body.rtl .view-more-container-bottom { direction:rtl; }
|
|||
|
||||
|
||||
#popup-external-profile .profile-card,
|
||||
#popup-external-profile .profile-card .profile-banner-footer {
|
||||
#popup-external-profile .profile-card .profile-banner-footer,
|
||||
#popup-local-profile .profile-card,
|
||||
#popup-local-profile .profile-card .profile-banner-footer {
|
||||
border-radius:0;
|
||||
}
|
||||
#popup-external-profile ul.queet-actions {
|
||||
#popup-external-profile ul.queet-actions,
|
||||
#popup-local-profile ul.queet-actions {
|
||||
display:none;
|
||||
}
|
||||
#popup-external-profile .queet,
|
||||
#popup-external-profile .queet-content,
|
||||
#popup-external-profile .queet-text {
|
||||
#popup-external-profile .queet-text
|
||||
#popup-local-profile .queet,
|
||||
#popup-local-profile .queet-content,
|
||||
#popup-local-profile .queet-text {
|
||||
cursor:auto;
|
||||
border-bottom:0 none;
|
||||
}
|
||||
#popup-external-profile .stream-item .stream-item-header .name:before {
|
||||
#popup-external-profile .stream-item .stream-item-header .name:before,
|
||||
#popup-local-profile .stream-item .stream-item-header .name:before {
|
||||
left:10px;
|
||||
}
|
||||
#popup-external-profile .go-to-external-profile {
|
||||
#popup-external-profile .go-to-external-profile,
|
||||
#popup-local-profile .go-to-local-profile {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
@ -3507,6 +3515,12 @@ button.shorten:after {
|
|||
top: 20px;
|
||||
}
|
||||
|
||||
#popup-external-profile-spinner .loader,
|
||||
#popup-local-profile-spinner .loader {
|
||||
position:absolute;
|
||||
top:150px;
|
||||
}
|
||||
|
||||
.reload-stream {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
|
|
@ -147,19 +147,19 @@ function getFromAPI(stream, actionOnSuccess) {
|
|||
|
||||
displayOrHideUnreadNotifications(request.getResponseHeader('Qvitter-Notifications'));
|
||||
|
||||
// profile card from user array
|
||||
// profile card from user array, also cache it
|
||||
if(request.getResponseHeader('Qvitter-User-Array') !== null) {
|
||||
addProfileCardToDOM(
|
||||
buildProfileCard(
|
||||
iterateRecursiveReplaceHtmlSpecialChars(
|
||||
$.parseJSON(
|
||||
request.getResponseHeader('Qvitter-User-Array')))));
|
||||
var userArray = iterateRecursiveReplaceHtmlSpecialChars($.parseJSON(request.getResponseHeader('Qvitter-User-Array')));
|
||||
userArrayCacheStore(userArray);
|
||||
addProfileCardToDOM(buildProfileCard(userArray));
|
||||
}
|
||||
|
||||
data = convertEmptyObjectToEmptyArray(data);
|
||||
|
||||
data = iterateRecursiveReplaceHtmlSpecialChars(data);
|
||||
|
||||
searchForUserDataToCache(data);
|
||||
|
||||
actionOnSuccess(data);
|
||||
},
|
||||
error: function(data) {
|
||||
|
|
|
@ -277,9 +277,8 @@ function buildExternalProfileCard(data) {
|
|||
emptyWebpage = ' empty';
|
||||
}
|
||||
|
||||
var serverUrl = data.statusnet_profile_url.replace('/' + data.screen_name,'');
|
||||
var userApiUrl = serverUrl + '/api/statuses/user_timeline.json?screen_name=' + data.screen_name;
|
||||
data.screenNameWithServer = '@' + data.screen_name + '@' + serverUrl.replace('http://','').replace('https://','');
|
||||
var serverUrl = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(data.statusnet_profile_url, data.screen_name);
|
||||
data.screenNameWithServer = '@' + data.screen_name + '@' + serverUrl;
|
||||
var followButton = '<div class="user-actions"><button' + followLocalIdHtml + ' data-follow-user="' + data.statusnet_profile_url + '" type="button" class="qvitter-follow-button ' + followingClass + '"><span class="button-text follow-text"><i class="follow"></i>' + window.sL.userFollow + '</span><span class="button-text following-text">' + window.sL.userFollowing + '</span><span class="button-text unfollow-text">' + window.sL.userUnfollow + '</span></button></div>';
|
||||
|
||||
data.profileCard = '\
|
||||
|
@ -343,6 +342,50 @@ function addProfileCardToDOM(data) {
|
|||
}
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Open external profile card in popup
|
||||
·
|
||||
· @param data: an object with a user array
|
||||
·
|
||||
· · · · · · · · · */
|
||||
|
||||
function openExternalProfileInPopup(data) {
|
||||
|
||||
var data = buildExternalProfileCard(data);
|
||||
|
||||
// preview latest notice
|
||||
var noticeHtml = '';
|
||||
if(typeof data.status != 'undefined') {
|
||||
data.status.user = data;
|
||||
var noticeHtml = buildQueetHtml(data.status);
|
||||
}
|
||||
|
||||
popUpAction('popup-external-profile', data.screenNameWithServer,data.profileCard + noticeHtml,'<a class="go-to-external-profile" href="' + data.statusnet_profile_url + '">' + window.sL.goToExternalProfile + '</a>');
|
||||
}
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Open local profile card in popup
|
||||
·
|
||||
· @param data: an object with a user array
|
||||
·
|
||||
· · · · · · · · · */
|
||||
|
||||
function openLocalProfileInPopup(data) {
|
||||
|
||||
var data = buildProfileCard(data);
|
||||
|
||||
// preview latest notice
|
||||
var noticeHtml = '';
|
||||
if(typeof data.status != 'undefined') {
|
||||
data.status.user = data;
|
||||
var noticeHtml = buildQueetHtml(data.status);
|
||||
}
|
||||
|
||||
popUpAction('popup-local-profile', '@' + data.screen_name, data.profileCardHtml + '<div class="clearfix"></div>' + noticeHtml,'<a class="go-to-local-profile" href="' + data.statusnet_profile_url + '">' + window.sL.goToExternalProfile + '</a>');
|
||||
}
|
||||
|
||||
|
||||
/* ·
|
||||
|
|
|
@ -216,6 +216,185 @@ function checkLocalStorage() {
|
|||
console.log(corrected + ' entries corrected, ' + deleted + ' entries deleted');
|
||||
}
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· User array cache
|
||||
·
|
||||
· Stored in window.userArrayCache as instance_url/nickname
|
||||
· with protocol (http:// or https://) trimmed off, e.g. "quitter.se/hannes2peer"
|
||||
·
|
||||
· · · · · · · · · */
|
||||
|
||||
window.userArrayCache = new Object();
|
||||
|
||||
function userArrayCacheStore(data) {
|
||||
|
||||
if(typeof data == 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we are passed a data object with both local and external data, use external data as key
|
||||
if(typeof data.local != 'undefined'
|
||||
&& typeof data.local.statusnet_profile_url != 'undefined'
|
||||
&& typeof data.external != 'undefined'
|
||||
&& typeof data.external.statusnet_profile_url != 'undefined') {
|
||||
var instanceUrlWithoutProtocol = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(data.external.statusnet_profile_url, data.external.screen_name);
|
||||
var key = instanceUrlWithoutProtocol + '/' + data.external.screen_name;
|
||||
var dataToStore = data;
|
||||
}
|
||||
// we can also get either local...
|
||||
else if(typeof data.local != 'undefined' && typeof data.local.statusnet_profile_url != 'undefined' ) {
|
||||
var instanceUrlWithoutProtocol = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(data.local.statusnet_profile_url, data.external.screen_name);
|
||||
var key = instanceUrlWithoutProtocol + '/' + data.external.screen_name;
|
||||
data.external = false;
|
||||
var dataToStore = data;
|
||||
}
|
||||
// ...or external...
|
||||
else if(typeof data.external != 'undefined' && typeof data.external.statusnet_profile_url != 'undefined' ) {
|
||||
var instanceUrlWithoutProtocol = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(data.external.statusnet_profile_url, data.external.screen_name);
|
||||
var key = instanceUrlWithoutProtocol + '/' + data.external.screen_name;
|
||||
data.local = false;
|
||||
var dataToStore = data;
|
||||
}
|
||||
// ...or an unspecified data object, in which case we check the avatar urls to see if it's local or external
|
||||
else if (typeof data.statusnet_profile_url != 'undefined') {
|
||||
var instanceUrlWithoutProtocol = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(data.statusnet_profile_url, data.screen_name);
|
||||
var key = instanceUrlWithoutProtocol + '/' + data.screen_name;
|
||||
|
||||
var dataProfileImageUrlWithoutProtocol = removeProtocolFromUrl(data.profile_image_url);
|
||||
var siteInstanceURLWithoutProtocol = removeProtocolFromUrl(window.siteInstanceURL);
|
||||
|
||||
// local
|
||||
if(dataProfileImageUrlWithoutProtocol.substring(0,siteInstanceURLWithoutProtocol.length) == siteInstanceURLWithoutProtocol){
|
||||
var dataToStore = {local:data,external:false};
|
||||
}
|
||||
// external
|
||||
else {
|
||||
var dataToStore = {external:data,local:false};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// store
|
||||
if(typeof window.userArrayCache[key] == 'undefined') {
|
||||
window.userArrayCache[key] = dataToStore;
|
||||
}
|
||||
else {
|
||||
if(dataToStore.local) {
|
||||
|
||||
// keep old status if newer data doesn't have any
|
||||
if(typeof dataToStore.local.status == 'undefined' && typeof window.userArrayCache[key].local.status != 'undefined') {
|
||||
dataToStore.local.status = window.userArrayCache[key].local.status;
|
||||
}
|
||||
|
||||
window.userArrayCache[key].local = dataToStore.local;
|
||||
}
|
||||
if(dataToStore.external) {
|
||||
window.userArrayCache[key].external = dataToStore.external;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function userArrayCacheGetByLocalNickname(localNickname) {
|
||||
if(typeof window.userArrayCache[window.siteRootDomain + '/' + localNickname] != 'undefined') {
|
||||
return window.userArrayCache[window.siteRootDomain + '/' + localNickname];
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function userArrayCacheGetByProfileUrlAndNickname(profileUrl, nickname) {
|
||||
var guessedInstanceUrl = guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(profileUrl, nickname);
|
||||
if(typeof window.userArrayCache[guessedInstanceUrl + '/' + nickname] == 'undefined') {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return window.userArrayCache[guessedInstanceUrl + '/' + nickname];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Guess instance's base installation url without protocol from a profile url
|
||||
·
|
||||
· · · · · · · · · */
|
||||
|
||||
function guessInstanceUrlWithoutProtocolFromProfileUrlAndNickname(profileUrl, nickname) {
|
||||
|
||||
// remove protocol
|
||||
var guessedInstanceUrl = removeProtocolFromUrl(profileUrl)
|
||||
|
||||
// user/id-style profile urls
|
||||
if(guessedInstanceUrl.indexOf('/user/') > -1 &&
|
||||
$.isNumeric(guessedInstanceUrl.substring(guessedInstanceUrl.lastIndexOf('/user/')+6))) {
|
||||
guessedInstanceUrl = guessedInstanceUrl.substring(0,guessedInstanceUrl.lastIndexOf('/user/'));
|
||||
}
|
||||
|
||||
// nickname-style profile urls
|
||||
else if(guessedInstanceUrl.substring(guessedInstanceUrl.lastIndexOf('/')+1) == nickname) {
|
||||
guessedInstanceUrl = guessedInstanceUrl.substring(0,guessedInstanceUrl.lastIndexOf('/'));
|
||||
}
|
||||
|
||||
// remove trailing "index.php" if the instance doesn't use mod_rewrite
|
||||
if(guessedInstanceUrl.substring(guessedInstanceUrl.lastIndexOf('/')) == '/index.php') {
|
||||
guessedInstanceUrl = guessedInstanceUrl.substring(0,guessedInstanceUrl.lastIndexOf('/'));
|
||||
}
|
||||
|
||||
// there was a bug once that made some instances have multiple /:s in their url,
|
||||
// so make sure there's no trailing /:s
|
||||
while (guessedInstanceUrl.slice(-1) == '/') {
|
||||
guessedInstanceUrl = guessedInstanceUrl.slice(0,-1);
|
||||
}
|
||||
|
||||
return guessedInstanceUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Remove the protocol (e.g. "http://") from an URL
|
||||
·
|
||||
· · · · · · · · · */
|
||||
|
||||
function removeProtocolFromUrl(url) {
|
||||
if(url.indexOf('://') == -1) {
|
||||
return url;
|
||||
}
|
||||
return url.substring(url.indexOf('://')+3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Iterates recursively through an API response in search for user data to cache
|
||||
· If we find a "statusnet_profile_url" key we assume the parent is a user array/object
|
||||
·
|
||||
· · · · · · · · · · · · · */
|
||||
|
||||
|
||||
function searchForUserDataToCache(obj) {
|
||||
for (var property in obj) {
|
||||
if (obj.hasOwnProperty(property)) {
|
||||
if (typeof obj[property] == "object") {
|
||||
searchForUserDataToCache(obj[property]);
|
||||
}
|
||||
else if(typeof obj[property] == 'string' && property == 'statusnet_profile_url') {
|
||||
userArrayCacheStore(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ·
|
||||
·
|
||||
· Display unread notifications
|
||||
|
@ -284,10 +463,8 @@ function iterateRecursiveReplaceHtmlSpecialChars(obj) {
|
|||
if (typeof obj[property] == "object") {
|
||||
iterateRecursiveReplaceHtmlSpecialChars(obj[property]);
|
||||
}
|
||||
else {
|
||||
if(typeof obj[property] == 'string' && property != 'statusnet_html' && property != 'source') {
|
||||
obj[property] = replaceHtmlSpecialChars(obj[property]);
|
||||
}
|
||||
else if(typeof obj[property] == 'string' && property != 'statusnet_html' && property != 'source') {
|
||||
obj[property] = replaceHtmlSpecialChars(obj[property]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
111
js/qvitter.js
111
js/qvitter.js
|
@ -936,6 +936,11 @@ $('body').on('click','a', function(e) {
|
|||
return;
|
||||
}
|
||||
|
||||
// if we're clicking something in a profile card popup, close it!
|
||||
if($(this).closest('#popup-local-profile, #popup-external-profile').length>0) {
|
||||
$('.modal-container').remove();
|
||||
}
|
||||
|
||||
// all links opens in new tab
|
||||
$(this).attr('target','_blank');
|
||||
|
||||
|
@ -969,8 +974,18 @@ $('body').on('click','a', function(e) {
|
|||
setNewCurrentStream('favorites.json',function(){},true);
|
||||
}
|
||||
// profiles
|
||||
else if ((/^[a-zA-Z0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/','')))) {
|
||||
var linkNickname = $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/','');
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var linkNickname = $(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/','');
|
||||
}
|
||||
|
||||
// don't hijack /groups-url
|
||||
if(linkNickname == 'groups') {
|
||||
|
@ -978,16 +993,51 @@ $('body').on('click','a', function(e) {
|
|||
}
|
||||
|
||||
e.preventDefault();
|
||||
if($(this).parent().attr('id') == 'user-profile-link') { // logged in user
|
||||
|
||||
// logged in user
|
||||
if($(this).parent().attr('id') == 'user-profile-link'
|
||||
|| linkNickname == window.loggedIn.screen_name) {
|
||||
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + window.loggedIn.screen_name,function(){},true);
|
||||
}
|
||||
else { // any user
|
||||
// when in local profile popups
|
||||
else if($(this).closest('#popup-local-profile').length>0) {
|
||||
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + linkNickname,function(){},true);
|
||||
}
|
||||
}
|
||||
else if((/^[0-9]+$/.test($(this).attr('href').replace('http://','').replace('https://','').replace(window.siteRootDomain + '/user/','')))) {
|
||||
e.preventDefault();
|
||||
setNewCurrentStream('statuses/user_timeline.json?screen_name=' + $(this).text().toLowerCase(),function(){},true);
|
||||
// any local user, not in popups –> open popup
|
||||
else {
|
||||
|
||||
$(this).addClass('local-profile-clicked');
|
||||
|
||||
popUpAction('popup-local-profile', '','<div id="popup-local-profile-spinner" style="height:300px;"></div>',false);
|
||||
display_spinner('#popup-local-profile-spinner');
|
||||
|
||||
// try getting from cache, to display immediately
|
||||
if($(this).hasClass('account-group')) {
|
||||
var localNickname = $(this).children('.screen-name').text().toLowerCase();
|
||||
}
|
||||
else {
|
||||
var localNickname = $(this).text().toLowerCase();
|
||||
}
|
||||
if(localNickname.substring(0,1) == '@') {
|
||||
localNickname = localNickname.substring(1);
|
||||
}
|
||||
var cachedUserArray = userArrayCacheGetByProfileUrlAndNickname($(this).attr('href'), localNickname);
|
||||
|
||||
if(cachedUserArray && cachedUserArray.local) {
|
||||
openLocalProfileInPopup(cachedUserArray.local);
|
||||
remove_spinner();
|
||||
$('.local-profile-clicked').removeClass('local-profile-clicked');
|
||||
}
|
||||
|
||||
// but always query the server also
|
||||
getFromAPI('users/show.json?id=' + localNickname,function(data){
|
||||
if(data) {
|
||||
openLocalProfileInPopup(data);
|
||||
remove_spinner();
|
||||
$('.local-profile-clicked').removeClass('local-profile-clicked');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// tags
|
||||
else if ($(this).attr('href').indexOf(window.siteRootDomain + '/tag/')>-1) {
|
||||
|
@ -1036,30 +1086,43 @@ $('body').on('click','a', function(e) {
|
|||
|| ($(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.loggedIn.screen_name != 'undefined') { // if logged in
|
||||
e.preventDefault();
|
||||
display_spinner();
|
||||
$(this).addClass('external-profile-clicked');
|
||||
|
||||
popUpAction('popup-external-profile', '','<div id="popup-external-profile-spinner" style="height:300px;"></div>',false);
|
||||
display_spinner('#popup-external-profile-spinner');
|
||||
|
||||
// try getting from cache, to display immediately
|
||||
if($(this).hasClass('account-group')) {
|
||||
var externalNickname = $(this).children('.screen-name').text();
|
||||
}
|
||||
else {
|
||||
var externalNickname = $(this).text();
|
||||
}
|
||||
if(externalNickname.substring(0,1) == '@') {
|
||||
externalNickname = externalNickname.substring(1);
|
||||
}
|
||||
var cachedUserArray = userArrayCacheGetByProfileUrlAndNickname($(this).attr('href'), externalNickname);
|
||||
|
||||
if(cachedUserArray && cachedUserArray.external) {
|
||||
openExternalProfileInPopup(cachedUserArray);
|
||||
remove_spinner();
|
||||
$('.external-profile-clicked').removeClass('external-profile-clicked');
|
||||
}
|
||||
|
||||
// but always query the server also
|
||||
getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent($(this).attr('href')),function(data){
|
||||
|
||||
if(data && data.external !== null) {
|
||||
|
||||
var data = buildExternalProfileCard(data);
|
||||
|
||||
// preview latest notice
|
||||
var noticeHtml = '';
|
||||
if(typeof data.status != 'undefined') {
|
||||
data.status.user = data;
|
||||
var noticeHtml = buildQueetHtml(data.status);
|
||||
}
|
||||
|
||||
popUpAction('popup-external-profile', data.screenNameWithServer,data.profileCard + noticeHtml,'<a class="go-to-external-profile" href="' + data.statusnet_profile_url + '">' + window.sL.goToExternalProfile + '</a>');
|
||||
|
||||
openExternalProfileInPopup(data);
|
||||
remove_spinner();
|
||||
$('a').removeClass('external-profile-clicked');
|
||||
|
||||
$('.external-profile-clicked').removeClass('external-profile-clicked');
|
||||
}
|
||||
// if external lookup failed, trigger click again.
|
||||
// if external lookup failed, and we don't have a cached profile card, trigger click again.
|
||||
// it will not be hijacked since we don't remove the external-profile-clicked class here
|
||||
else {
|
||||
remove_spinner();
|
||||
else if($('#popup-external-profile-spinner').length > 0){
|
||||
$('.modal-container').remove();
|
||||
$('.external-profile-clicked')[0].click();
|
||||
$('.external-profile-clicked').removeClass('external-profile-clicked');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user