// ==UserScript==
// @name BetterFetLife
// @namespace com.fetlife.better
// @include https://fetlife.com/*
// @version 1
// @grant none
// @description See website
// ==/UserScript==
$(document).ready(function(){
// add custom css
$('head').append('<style type="text/css">' + bfl_css + '</style>');
// === USER POPUP === //
// create user popup
$('body').append(' ' +
' <div id="bfl-user"> ' +
' <a class="avatar-wrap"> ' +
' <div class="avatar"></div> ' +
' </a> ' +
' <a class="name"></a> ' +
' <span class="status"></span> ' +
' <span class="location"></span> ' +
' <span class="photos"></span> ' +
' </div> '
);
// show a user popup on hover
$('a[href^="/users/"], a[href^="https://fetlife.com/users/"').live('mouseover', $.debounce( 250, function(){
var linkEl = this;
var href = $(linkEl).attr('href');
href = href.replace('https://fetlife.com', '');
// prevent non-user links
if( href.split('/').length != 3 ) return;
// prevent self-links
if( $(linkEl).closest('#bfl-user').length > 0 ) return;
// prevent closing
clearTimeout(hideUserPopupTimeout);
// reset the popup
hideUserPopup();
// show the popup
$('#bfl-user')
.addClass('loading')
.css({
top: $(linkEl).offset().top + $(linkEl).height() + 8,
left: $(linkEl).offset().left
})
.show();
$.ajax({
url: href,
dataType: "html",
// cache is OK
cache: true,
// prevent 503, fetlife don't liking ajax calls
beforeSend: function(xhr) {
xhr.setRequestHeader(
'X-Requested-With',
{
toString: function() { return ''; }
}
);
},
success: function(userDOM){
var userAvatarEl = $(userDOM).find('#main_content a img');
// avatar href
$('#bfl-user')
.attr('avatar-href', $(userAvatarEl).attr('src'));
// avatar
$('#bfl-user .avatar-wrap')
.attr('href', href)
$('#bfl-user .avatar')
.css('background-image', 'url(' + $(userAvatarEl).attr('src') + ')')
// name
$('#bfl-user .name')
.attr('href', href)
.html( $(userAvatarEl).attr('alt') );
// status (age+gender+orientation)
$('#bfl-user .status')
.html( $(userDOM).find('#profile h2 .small').html() );
// location
$('#bfl-user .location')
.html( $(userDOM).find('#profile h2.bottom + p').html() );
window.userDOM = userDOM;
// photos
var photos = $(userDOM).find('#profile .container a[href^="/users/"][href*="/pictures"]');
photos = photos.filter(function(){
return $(this).find('img').length > 0;
})
photos = photos.slice(0,5);
$('#bfl-user .photos')
.html('')
.append( photos );
// friends status
// remove the link first
$(userDOM).find('.friends_badge').find('a').remove()
$('#bfl-user .friends_status')
.html( $(userDOM).find('.friends_badge').text() );
$('#bfl-user')
.removeClass('loading')
}
});
})).live('mouseleave', function(e){
var linkEl = this;
var href = $(linkEl).attr('href');
// prevent non-user links
if( href.split('/').length != 3 ) return;
clearTimeout(hideUserPopupTimeout);
console.log('a mouseleave');
hideUserPopupTimeout = setTimeout(hideUserPopup, hideUserPopupDelay);
});
$('#bfl-user').live('mouseover', function(e){
clearTimeout(hideUserPopupTimeout);
});
$('#bfl-user').live('mouseleave', function(e){
clearTimeout(hideUserPopupTimeout);
console.log('bfl-user mouseleave');
hideUserPopupTimeout = setTimeout(hideUserPopup, hideUserPopupDelay);
});
var hideUserPopupTimeout = setTimeout('', 0);
var hideUserPopupDelay = 500;
function hideUserPopup() {
$('#bfl-user .avatar').attr('style', '');
$('#bfl-user .name').html('').attr('href', '');
$('#bfl-user .status').html('');
$('#bfl-user .location').html('');
$('#bfl-user .friends_badge').html('');
$('#bfl-user .photos').html('');
$('#bfl-user').removeClass('loading');
$('#bfl-user').hide();
}
// === IMAGE POPUP === //
// create image popup
$('body').append(' ' +
' <div id="bfl-image"> ' +
' <span class="header"> ' +
' <span class="title"></span> ' +
' <span class="like-wrap"> ' +
' <span class="like-count"></span> ' +
' <span class="like picto">k</span> ' +
' </span> ' +
' </span> ' +
' <a class="image-wrap"> ' +
' <img class="image" /> ' +
' </a> ' +
' </div> '
);
$('a[href^="/users/"][href*="/pictures"], a[href^="https://fetlife.com/users/"][href*="/pictures"]').live('mouseover', $.debounce( 250, function(){
var linkEl = this;
var href = $(this).attr('href');
href = href.replace('https://fetlife.com', '');
// prevent non-image links
if( href.split('/').length != 5 ) return;
// prevent self-links
if( $(linkEl).closest('#bfl-image').length > 0 ) return;
// reset the popup
hideImagePopup();
// show the popup
var css = {
top: $(linkEl).offset().top + $(linkEl).height() + 8
}
if( $(linkEl).offset().left > $(window).width()/2 ) {
css.right = $(window).width() - $(linkEl).offset().left - $(linkEl).width();
$('#bfl-image').addClass('alignright');
} else {
css.left = $(linkEl).offset().left;
}
$('#bfl-image')
.addClass('loading')
.css(css)
.show();
$.ajax({
url: href,
dataType: "html",
success: function(html){
var title = $(html).find('.s.i.caption').text();
var likeUrl = href.split('/');
likeUrl = likeUrl[ likeUrl.length-1 ];
likeUrl = "/pictures/" + likeUrl + "/likes"
// extract the image src
var src = $(html).find('style').first().html().match(/\(\'(.*?)\'\)/);
src = src[0];
src = src.replace("('", "");
src = src.replace("')", "");
$('#bfl-image .title')
.html(title)
.attr('title', title)
$('#bfl-image .like-wrap')
.attr('data-href', likeUrl);
$('#bfl-image .image-wrap')
.attr('href', href);
$('#bfl-image .image')
.load(function(){
$('#bfl-image').removeClass('loading')
})
.attr('src', src)
// get amount of likes
$.ajax({
url: likeUrl,
dataType: "json",
success: function(data) {
$('#bfl-image .like-wrap').toggle(data.user_can_like);
if( data.is_liked_by_user ) {
$('#bfl-image .like-wrap').addClass('liked');
}
$('#bfl-image .like-count')
.html(data.total);
}
});
}
});
})).live('mouseleave', function(e){
var linkEl = this;
var href = $(linkEl).attr('href');
// prevent non-user links
if( href.split('/').length != 3 ) return;
clearTimeout(hideImagePopupTimeout);
hideImagePopupTimeout = setTimeout(hideImagePopup, hideImagePopupDelay);
});
$('#bfl-image').live('mouseover', function(e){
clearTimeout(hideImagePopupTimeout);
clearTimeout(hideUserPopupTimeout);
});
$('#bfl-image').live('mouseleave', function(e){
clearTimeout(hideImagePopupTimeout);
hideImagePopupTimeout = setTimeout(hideImagePopup, hideImagePopupDelay);
});
var hideImagePopupTimeout = setTimeout('', 0);
var hideImagePopupDelay = 500;
function hideImagePopup() {
$('#bfl-image .title').html('').attr('href', '');
$('#bfl-image .image').attr('src', '');
$('#bfl-image .like-wrap').attr('data-href', '');
$('#bfl-image .like-count').html('');
$('#bfl-image').removeClass('loading');
$('#bfl-image').removeClass('alignright');
$('#bfl-image').hide();
}
$('#bfl-image .like-wrap').live('click', function(){
var this_ = this;
$.ajax({
url: $(this_).data('href') + '/toggle',
type: 'post',
success: function(){
if( $(this_).hasClass('liked') ) {
$('#bfl-image .like-count').html( parseInt( $('#bfl-image .like-count').html()) - 1 )
} else {
$('#bfl-image .like-count').html( parseInt( $('#bfl-image .like-count').html()) + 1 )
}
$(this_).toggleClass('liked');
}
});
return false;
});
});
var bfl_css = '' +
' #bfl-user {' +
' position: absolute;' +
' z-index: 100;' +
' display: none;' +
' padding: 4px;' +
' min-width: 180px;' +
' height: 80px;' +
' padding-left: 92px;' +
' padding-right: 8px;' +
' background: #323232;' +
' border: 3px solid #171717;' +
' }' +
' #bfl-user.loading {' +
' padding-left: 84px;' +
' padding-right: 4px;' +
' min-width: 0;' +
' }' +
' #bfl-user:before,' +
' #bfl-image:before {' +
' position: absolute;' +
' z-index: 101;' +
' display: block;' +
' content: "";' +
' left: 7px;' +
' top: -8px;' +
' border: 8px solid transparent;' +
' border-bottom-color: #171717;' +
' border-top-width: 0;' +
' }' +
' #bfl-user:after,' +
' #bfl-image:after {' +
' position: absolute;' +
' z-index: 102;' +
' display: block;' +
' content: "";' +
' left: 10px;' +
' top: -5px;' +
' border: 5px solid transparent;' +
' border-bottom-color: #323232;' +
' border-top-width: 0;' +
' }' +
' #bfl-user .avatar {' +
' position: absolute;' +
' left: 4px;' +
' width: 80px;' +
' height: 80px;' +
' padding: 0px;' +
' margin-right: 8px;' +
' background-color: transparent;' +
' background-size: cover;' +
' background-position: center center;' +
' background-repeat: no-repeat;' +
' }' +
' #bfl-user.loading .avatar {' +
' background-size: auto;' +
' background-image: url(https://flassets.a.ssl.fastly.net/std/spinners/circle_big.gif);' +
' margin-right: 0;' +
' }' +
' #bfl-user .name {' +
' white-space: nowrap;' +
' }' +
' #bfl-user .status {' +
' white-space: nowrap;' +
' color: #aaa;' +
' }' +
' #bfl-user .location {' +
' display: block;' +
' font-size: 12px;' +
' white-space: nowrap;' +
' }' +
' #bfl-user .friends_status {' +
' float: right;' +
' font-size: 12px;' +
' }' +
' #bfl-user .photos {' +
' position: absolute;' +
' right: 4px;' +
' bottom: 4px;' +
' font-size: 12px;' +
' }' +
' #bfl-user .photos a {' +
' float: left;' +
' font-size: 12px;' +
' }' +
' #bfl-user .photos a img {' +
' float: left;' +
' margin: 2px;' +
' width: 25px;' +
' height: 25px;' +
' padding: 0;' +
' }' +
' #bfl-image {' +
' position: absolute;' +
' z-index: 100;' +
' display: none;' +
' background: #323232;' +
' border: 3px solid #171717;' +
' padding: 4px;' +
' }' +
' #bfl-image.alignright:before {' +
' left: auto;' +
' right: 7px;' +
' }' +
' #bfl-image.alignright:after {' +
' left: auto;' +
' right: 10px;' +
' }' +
' #bfl-image.loading {' +
' width: 80px;' +
' height: 80px;' +
' background: #323232 url(https://flassets.a.ssl.fastly.net/std/spinners/circle_big.gif) no-repeat center center;' +
' }' +
' #bfl-image .header {' +
' position: absolute;' +
' left: 0;' +
' right: 0;' +
' top: 0;' +
' background: #323232;' +
' padding: 4px;' +
' overflow: hidden;' +
' font-size: 12px;;' +
' }' +
' #bfl-image.loading .header {' +
' display: none;' +
' }' +
' #bfl-image .title {' +
' float: left;' +
' width: 80%;' +
' white-space: nowrap;' +
' overflow: hidden;' +
' text-overflow: ellipsis;' +
' }' +
' #bfl-image .like-wrap {' +
' float: right;' +
' width: 10%;' +
' white-space: nowrap;' +
' text-align: right;' +
' cursor: pointer;' +
' }' +
' #bfl-image .like-wrap:hover {' +
' color: #ffffff;' +
' }' +
' #bfl-image .like-wrap:active {' +
' color: #bbbbbb;' +
' }' +
' #bfl-image .like-wrap.liked {' +
' color: #DD0000;' +
' }' +
' #bfl-image .like-wrap.liked:hover {' +
' color: #FF0000;' +
' }' +
' #bfl-image .like-wrap.liked:active {' +
' color: #BB0000;' +
' }' +
' #bfl-image .image {' +
' display: block;' +
' padding: 0;' +
' }' +
/*
* jQuery throttle / debounce - v1.1 - 3/7/2010
* http://benalman.com/projects/jquery-throttle-debounce-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);