There are 12 previous versions of this script.
// ==UserScript==
// @name Best Friends for StumbleUpon
// @namespace thlayli.detrave.net
// @description Adds a section for Best Friends on SU
// @include http://*.stumbleupon.com/friends/*
// @license http://www.gnu.org/copyleft/gpl.html
// @version 2.6.3
// ==/UserScript==
// auto-update variables
var script_title = 'Best Friends for StumbleUpon';
var source_location = 'http://thlayli.detrave.net/su-bestfriends.user.js';
var version_holder = 'http://thlayli.detrave.net/su-bestfriends.version.txt';
var current_version = '2.6.3';
var latest_version = '';
var manual_check = true;
var lastupdatecheck = GM_getValue('Updated', 'never');
GM_registerMenuCommand('Update - '+script_title, CheckVersion);
CheckForUpdate();
var editFlag = 0;
var aboutFlag = 0;
var fullFriends = 1;
var fullSubscribers = 1;
var friendBfs = new Array();
var subBfs = new Array();
var uniqueBfs = new Array();
var whatsNew = xpath(document, "//a[contains(@href, 'stumbleupon.com/prefs/' )]");
var isYourPage = (whatsNew.snapshotLength > 0) ? 1 : 0;
var allFriends = xpath(document,"//dl[contains(@class, 'vcardLg')]");
var friendLoad = false;
var subLoad = false;
var subnavDiv = xpath(document, "//div[@class='subnav']").snapshotItem(0);
var bgColor = getStyle(subnavDiv, 'background-color');
// get user name
var publicLink = xpath(document, "//a[contains(@href, '.stumbleupon.com/public/')]").snapshotItem(0);
var userName = publicLink.href.match(/http:\/\/([^\.]+)\.stumbleupon\.com\/public\//)[1];
var thisStumbler = publicLink.textContent;
// clean up mess from silly bug in v2.6 - remove in 2.6.4
if(GM_getValue('Thlayli','') != '' && GM_getValue(thisStumbler,'') == ''){
GM_setValue(thisStumbler,GM_getValue('Thlayli',''));
GM_deleteValue('Thlayli','');
}
if(isYourPage == 1){
// get logged in name
var friendsPref = GM_getValue(thisStumbler,'');
var friendsList = (friendsPref.indexOf(';')) ? friendsPref.split(';') : new Array();
friendsList = friendsList.sort(sortFriends);
var friendsCount = friendsList.length;
if(friendsList[0] == '')
var friendsCount=0;
//create bf section
if(document.location.pathname.indexOf('/fans/') == -1){
var friendBar = xpath(document, "//h1[contains(., ' friends')]").snapshotItem(0);
if(document.location.pathname.indexOf('/all/') == -1){
var subscriberContent = xpath(document,"//h1[contains(., 'Your subscriptions')]").snapshotItem(0);
if(subscriberContent){
subscriberContent = subscriberContent.nextSibling.nextSibling.nextSibling.nextSibling;
//check for "Who are they?" link
if(subscriberContent.textContent.indexOf('see their favorites') != -1)
subscriberContent = subscriberContent.nextSibling.nextSibling;
}
}
}else{
var friendBar = xpath(document, "//h1[contains(., ' subscribers')]").snapshotItem(0);
}
var subscriptionLinks = friendBar.parentNode.parentNode.nextSibling.nextSibling.firstChild.firstChild.nextSibling;
var subscriptionContent = subscriptionLinks.nextSibling.nextSibling;
var newFriendBar = friendBar.cloneNode(true);
var bfLinks = subscriptionLinks.cloneNode(true);
var bfContent = subscriptionContent.cloneNode(true);
bfContent.innerHTML = '\n';
var bfInsertSpot = friendBar.parentNode.parentNode.nextSibling.nextSibling.firstChild;
bfInsertSpot.insertBefore(newFriendBar,bfInsertSpot.firstChild);
bfInsertSpot.insertBefore(bfContent,bfInsertSpot.firstChild);
bfInsertSpot.insertBefore(bfLinks,bfInsertSpot.firstChild);
friendBar.innerHTML = 'Your best friends <span class="textXSm textNoEm textUncolor">(' + friendsCount + ')</span>';
bfLinks.innerHTML = '<ul class="cmds"><li class="textlink" style="display: none;"><a href="javascript:void(0);" class="textlink" id="edit_bf">Edit best friends</a></li><li class="textlink" style="display: none;"><a href="javascript:void(0);" class="textlink" id="cancel_edit">Cancel edit</a></li></ul><div class="clear"><!-- --></div>';
//create full content sections
var fullFriendsContent = subscriptionContent.cloneNode(true);
fullFriendsContent.style.display = 'none';
fullFriendsContent.setAttribute('rel', 'full_friends');
subscriptionContent.parentNode.insertBefore(fullFriendsContent,subscriptionContent);
if(subscriberContent){
var fullSubscribersContent = subscriberContent.cloneNode(true);
fullSubscribersContent.style.display = 'none';
fullSubscribersContent.setAttribute('rel', 'full_subscriptions');
subscriberContent.parentNode.insertBefore(fullSubscribersContent,subscriberContent);
}
var moreFriends = xpath(document, "//a[contains(@href, 'friends/all/')]").snapshotItem(0);
if(moreFriends){
moreFriends.href = 'javascript: void(0);';
moreFriends.wrappedJSObject.addEventListener('click', toggleFriendLists, true);
}
var moreSubscriptions = xpath(document, "//a[contains(@href, 'subscriptions/')]").snapshotItem(0);
if(moreSubscriptions){
moreSubscriptions.href = 'javascript: void(0);';
moreSubscriptions.wrappedJSObject.addEventListener('click', toggleSubscriptionLists, true);
}
//check for About Link modification
if(subscriptionContent.firstChild.nextSibling.firstChild.nextSibling.firstChild.href.indexOf('/about/') != -1)
var aboutFlag = 1;
//edit & cancel event listeners
document.getElementById('edit_bf').wrappedJSObject.addEventListener('click', editFriends, true);
document.getElementById('cancel_edit').wrappedJSObject.addEventListener('click', cancelEdit, true);
//retrieve full list
if(document.location.pathname.indexOf('/friends/all/') == -1 && document.location.pathname.indexOf('/fans/') == -1 && document.location.pathname.indexOf('/subscriptions/') == -1){
//get content from all friends page
var friendLocation = document.location.href + 'all/';
GM_xmlhttpRequest({
method: 'GET',
url: friendLocation,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'text/html',
},
onload: function(responseDetails) {
var tempFriendsContent = responseDetails.responseText.split('<div class="listPeople mgnTop clearfix mgnBottom">');
tempFriendsContent = tempFriendsContent[1].split('</div>');
fullFriendsContent.innerHTML = tempFriendsContent[0];
if(document.location.pathname.indexOf('/friends/all/') == -1){
if(moreFriends){
subscriptionContent.parentNode.removeChild(subscriptionContent);
ffrElement = xpath(document, "//div[@rel='full_friends']").snapshotItem(0);
ffrElement.style.display = 'block';
}
}
removeDupes(fullFriendsContent);
updateFriendNumbers();
if(moreFriends)
toggleFriendLists();
friendLoad = true;
}
});
//get content from all subscriptions page
var subLocation = document.location.href.replace(/friends\//ig,'')+'subscriptions/';
GM_xmlhttpRequest({
method: 'GET',
url: subLocation,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'text/html',
},
onload: function(responseDetails) {
//take content from all friends page
var tempSubscribersContent = responseDetails.responseText.split('<div class="listPeople mgnTop clearfix mgnBottom">');
tempSubscribersContent = tempSubscribersContent[1].split('</div>');
fullSubscribersContent.innerHTML = tempSubscribersContent[0];
if(document.location.pathname.indexOf('/friends/all/') == -1){
if(subscriberContent){
subscriberContent.parentNode.removeChild(subscriberContent);
fsElement = xpath(document, "//div[@rel='full_subscriptions']").snapshotItem(0);
fsElement.style.display = 'block';
}
}
removeDupes(fullSubscribersContent);
updateSubNumbers();
if(moreSubscriptions)
toggleSubscriptionLists();
subLoad = true;
}
});
}
checkLoad();
}
function checkLoad(){
if(friendLoad == true && subLoad == true){
document.getElementById('edit_bf').parentNode.style.display = "";
writeBfs();
}
else
setTimeout(checkLoad,100);
}
function removeDupes(section){
allFriends = xpath(document,"//dl[contains(@class, 'vcardLg')]");
var offset = 0;
var toRemove = new Array();
for(n=friendsList.length-1;n>=0;n--){
for(i=0;i<allFriends.snapshotLength;i++){
var linkName = allFriends.snapshotItem(i).firstChild.nextSibling.textContent;
if(friendsList[n].split(',')[1] == linkName){
//count bfs
if(section.rel=='full_friends')
friendBfs.push(linkName);
if(section.rel=='full_subscriptions')
subBfs.push(linkName);
// check online status
if(allFriends.snapshotItem(i).firstChild.nextSibling.nextSibling.nextSibling){
//alert(allFriends.snapshotItem(i).firstChild.nextSibling.nextSibling.nextSibling.className);
var tempFriend = friendsList[n];
friendsList.splice(n,1);
friendsList.splice(friendsList.length - offset, 0, tempFriend + ',1');
offset++;
}
toRemove.push(i);
break;
}
}
}
//remove nodes
for(r=0;r<toRemove.length;r++)
allFriends.snapshotItem(toRemove[r]).parentNode.removeChild(allFriends.snapshotItem(toRemove[r]));
}
function writeBfs(){
fixAboutLinks();
allFriends = xpath(document,"//dl[contains(@class, 'vcardLg')]");
for(i=friendsList.length-1;i>=0;i--){
var bf = friendsList[i].split(',');
var bfOnline = '';
var bfAbout = '';
if(bf.length >= 3){
var bfOnlineTitle = "";
var bfImg = bf[0];
var bfName = bf[1];
var bfFavs = bf[2];
if(bf[3]){
var bfOnline = '<dd class="flairs"><img style="padding: 5px 5px 5px 0pt;" title="Online now" alt="Online now" src="http://cdn.stumble-upon.com/images/icon_online.gif"/></dd>';
var bfOnlineTitle = ' | Online now';
}
var bfTitle = bfName + " || " + bfFavs + " favorites" + bfOnlineTitle;
//if(aboutFlag == 1)
// bfAbout = 'about/';
var newBf = document.createElement('dl');
newBf.className = 'vcardLg bf';
newBf.innerHTML = '<dd class="thumbnail borderGreen"><a class="tips" style="background-image: url(http://cdn.stumble-upon.com/'+bfImg+'.jpg);" title="'+bfTitle+'" href="http://'+bfName+'.stumbleupon.com/"/></dd><dt><a href="http://'+bfName.toLowerCase()+'.stumbleupon.com/">'+bfName+'</a></dt><dd class="stats"><a title="Stumble!|See '+bfName+'\'s favorites" class="tips" ondblclick="stumble_thru" href="http://www.stumbleupon.com/through.php?mode=user&user='+bfName+'">'+bfFavs+' favs</a></dd>'+bfOnline;
bfContent.appendChild(newBf);
}
}
}
function fixAboutLinks(){
if(aboutFlag==1){
var docLinks = xpath(document,'//a');
for(i=0;i<docLinks.snapshotLength;i++){
if(docLinks.snapshotItem(i).href.match(/^http:\/\/www|^http:\/\/buzz.stumbleupon|^javascript|.group.stumbleupon.com|about\/$/i) == null && docLinks.snapshotItem(i).href.indexOf('stumbleupon.com/') != -1 && docLinks.snapshotItem(i).href.indexOf('http://'+thisStumbler.toLowerCase()) == -1 && docLinks.snapshotItem(i).href.split('/').length < 5)
docLinks.snapshotItem(i).href = docLinks.snapshotItem(i).href + 'about/';
}
}
}
function updateFriendNumbers(){
if(friendBfs.length > 0){
var plural = (friendBfs.length == 1) ? 'friend' : 'friends';
var friendLabel = xpath(document, "//h1[contains(., 'Your friends')]").snapshotItem(0);
var friendNumber = friendLabel.innerHTML.split('(')[1].replace(')', '');
friendLabel.innerHTML = 'Your friends <span class="textXSm textNoEm textUncolor">(' + (parseInt(friendNumber) - friendBfs.length) + ' + ' + friendBfs.length + ' best ' + plural + ')</span>';
}
}
function updateSubNumbers(){
if(subBfs.length > 0){
var plural = (subBfs.length == 1) ? 'friend' : 'friends';
var yourSubscribersLabel = xpath(document, "//h1[contains(., 'Your subscriptions')]").snapshotItem(0);
var yourSubscribersNumber = yourSubscribersLabel.innerHTML.split('(')[1].replace(')', '');
yourSubscribersLabel.innerHTML = 'Your subscriptions <span class="textXSm textNoEm textUncolor">(' + (parseInt(yourSubscribersNumber) - subBfs.length) + ' + ' + subBfs.length + ' best ' + plural + ')</span>';
}
}
function toggleFriendLists(){
ffrElement = xpath(document, "//div[@rel='full_friends']").snapshotItem(0);
var fullFriendsList = xpath(ffrElement,'dl');
if(fullFriends == 1){
moreFriends.innerHTML = 'Show all friends';
fullFriends = 0;
for(i=15;i<fullFriendsList.snapshotLength;i++)
fullFriendsList.snapshotItem(i).style.display = 'none';
}else{
moreFriends.innerHTML = 'Show fewer friends';
fullFriends = 1;
for(i=15;i<fullFriendsList.snapshotLength;i++)
fullFriendsList.snapshotItem(i).style.display = 'block';
}
}
function toggleSubscriptionLists(){
fsElement = xpath(document, "//div[@rel='full_subscriptions']").snapshotItem(0);
var fullSubscribersList = xpath(fsElement,'dl');
if(fullSubscribers == 1){
moreSubscriptions.innerHTML = 'Show all subscriptions';
fullSubscribers = 0;
for(i=15;i<fullSubscribersList.snapshotLength;i++)
fullSubscribersList.snapshotItem(i).style.display = 'none';
}else{
moreSubscriptions.innerHTML = 'Show fewer subscriptions';
fullSubscribers = 1;
for(i=15;i<fullSubscribersList.snapshotLength;i++)
fullSubscribersList.snapshotItem(i).style.display = 'block';
}
}
function markFriend(evt){
if(evt){
var elem = (evt.target) ? evt.target : evt.srcElement;
if(elem.nodeName == "DL")
markElem = elem;
else if(elem.parentNode.nodeName == "DL")
markElem = elem.parentNode;
else if(elem.parentNode.parentNode.nodeName == "DL")
markElem = elem.parentNode.parentNode;
if(!markElem.style.backgroundColor){
markElem.style.backgroundColor = bgColor;
}else{
markElem.style.backgroundColor = "";
}
}
return false;
}
function cancelEdit(){
window.location.reload();
}
function editFriends(){
allFriends = xpath(document,"//dl[contains(@class, 'vcardLg')]");
if(editFlag == 0){
//edit
if(subscriberContent){
if(moreFriends){
fullFriends = 0;
toggleFriendLists();
}
if(moreSubscriptions){
fullSubscribers = 0;
toggleSubscriptionLists();
}
}
document.getElementById('edit_bf').innerHTML = 'Save best friends';
document.getElementById('cancel_edit').parentNode.style.display = '';
for(i=0;i<allFriends.snapshotLength;i++){
if(allFriends.snapshotItem(i).childNodes.length <= 5){
allFriends.snapshotItem(i).wrappedJSObject.addEventListener('click', markFriend, false);
allFriends.snapshotItem(i).innerHTML = allFriends.snapshotItem(i).innerHTML.replace(/href=\"http:\/\/([^\.]+)\.stumbleupon.com\/\"|href=\"http:\/\/www\.stumbleupon\.com\/through\.php\?mode=user&user=\w*\"/g,'href="javascript:void(0);" alt="$1"');
}
}
editFlag=1;
}else{
//save
for(i=0;i<allFriends.snapshotLength;i++){
var friendLink = allFriends.snapshotItem(i).firstChild.nextSibling.firstChild;
var friendImg = allFriends.snapshotItem(i).firstChild.firstChild;
if(allFriends.snapshotItem(i).childNodes.length < 5)
allFriends.snapshotItem(i).wrappedJSObject.removeEventListener('click', markFriend, false);
if(allFriends.snapshotItem(i).className.match(/bf/)){
//remove best friend
if(friendLink && allFriends.snapshotItem(i).style.backgroundColor){
var linkName = friendLink.textContent.replace(/^\s+|\s+$/g,"");
for(n=0;n<friendsList.length;n++){
if(friendsList[n].split(',')[1]==linkName)
friendsList.splice(n,1);
}
}
}else{
//add best friend
if(friendLink && allFriends.snapshotItem(i).style.backgroundColor){
var friendImgSrc = friendImg.style.backgroundImage.replace(/url\(http:\/\/cdn\.stumble-upon\.com\/|\.jpg\)/ig,''); //add code to deal with no avatar
var favs = friendLink.parentNode.nextSibling.textContent.replace(" favs","");
friendsList.push(friendImgSrc+','+friendLink.getAttribute('alt')+','+favs);
}
}
}
editFlag=0;
if(friendsList[0] == '')
friendsList.shift();
friendsPref = (friendsList.length > 0) ? friendsList.join(';').replace(/,online/ig,'') : '';
GM_setValue(thisStumbler,friendsPref);
window.location.reload();
}
}
function sortFriends(a,b){
a = a.toLowerCase().split(',')[1];
b = b.toLowerCase().split(',')[1];
if (a<b) return 1;
if (a>b) return -1;
return 0;
}
function xpath(obj,query) {
return document.evaluate(query, obj, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}
function getStyle(oElm, strCssRule){
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
}
// Userscript Auto-Update - http://userscripts.org/scripts/show/22372 - edited July 18 2008 by Nathan Blume
function GetNewVersion() {
var today = new Date();
GM_setValue('Updated', String(today));
window.location = source_location;
}
function CheckForUpdate(){
var today = new Date();
var one_day = 24 * 60 * 60 * 1000; //One day in milliseconds
if(lastupdatecheck != 'never'){
today = today.getTime(); //Get today's date
lastupdatecheck = new Date(lastupdatecheck).getTime();
var interval = (today - lastupdatecheck) / one_day; //Find out how many days have passed
if(interval >= 7){
manual_check = false;
CheckVersion();
}
}else{
lastupdatecheck = new Date(lastupdatecheck).getTime();
manual_check = false;
CheckVersion();
}
}
function CheckVersion(){
GM_xmlhttpRequest({
method: 'GET',
url: version_holder,
headers: {'Content-type':'application/x-www-form-urlencoded'},
onload: function(responseDetails){
var latest_version = responseDetails.responseText.match(/version=([0-9\.]+)/);
if(latest_version[1] != null && latest_version[1] != 'undefined'){
if(current_version != latest_version[1]){
if(confirm('A more recent version of ' + script_title + ' (' + latest_version[1] + ') has been found.\nWould you like to get it now?'))
GetNewVersion();
else
AskForReminder();
}else{
SkipWeeklyUpdateCheck();
if(manual_check == true)
alert('You have the latest version of ' + script_title + '.');
}
}else{
alert('Sorry, there was problem checking for the update.\nPlease try again later.');
}
}
});
}
function AskForReminder(){
if(confirm('Would you like to be reminded in 24 hours ?\n(Cancel to be reminded in one week.)')){
var today = new Date();
today = today.getTime();
var sixdays_ms = 6 * 24 * 60 * 60 * 1000;
var sda_ms = today - sixdays_ms;
var sixdaysago = new Date(sda_ms)
GM_setValue('Updated', String(sixdaysago));
}else{
SkipWeeklyUpdateCheck();
}
}
function SkipWeeklyUpdateCheck(){
var today = new Date();
GM_setValue('Updated', String(today));
}