This is my flair:
这是我的天赋:
<a href="https://*.com/users/775964/mr-32">
<img src="http://www.itdaan.com/imgs/0/4/7/3/55/4e3f289fb6bb088dc681fa053993d0c5.jpe" width="208" height="58" alt="profile for Mr.32 at Stack Overflow, Q&A for professional and enthusiast programmers" title="profile for Mr.32 at Stack Overflow, Q&A for professional and enthusiast programmers">
</a>
Now on any question or any answer of any so user having more than 1000 repution has following effect when you move cursor on that user's signature on any answer/question, like this:
现在任何问题或任何答案如此,当你在任何答案/问题上移动光标在该用户的签名上时,具有超过1000次重复的用户具有以下效果,如下所示:
So can this effect can be made on flair code so when I paste that code onto my website it will give the Expanded view of my flair?
那么这个效果可以在天赋代码上进行,所以当我将该代码粘贴到我的网站上时,它会给出我的天赋的扩展视图吗?
1 个解决方案
#1
2
This is the code I have currently... I had to delete the rest to make it fit.
这是我目前的代码......我不得不删除其余部分以使其适合。
-- I cleaned up the code quite a bit, but let me know if I need to clarify something as I'm not the best at documenting.
- 我清理了相当多的代码,但是如果我需要澄清一些内容,请告诉我,因为我不是最好的文档。
This is the js that was named "so.js"
这是名为“so.js”的js
/*
* author: craniumonempty
* javascript/jquery for user dropdown over user flair for user sites (designed with *, but should be easily adapted)
* to be used in conjuntion with php
*
* Nothing to be called, it searches for all * flair (as given by website with <a><img></a>) on page
*
* This requires JQquery 1.5 or newer due to the $.getJSON().success() function call
*/
/* Minimal html to test:
<html><head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="so.js"></script>
</head><body>
<a href="http://*.com/users/540753/craniumonempty">
<img src="http://*.com/users/flair/540753.png" width="208" height="58" alt="profile for craniumonempty at Stack Overflow, Q&A for professional and enthusiast programmers" title="profile for craniumonempty at Stack Overflow, Q&A for professional and enthusiast programmers">
</a>
</body></html>
Note, jquery >= 1.5 and tag (<a><img></a>) with the * site. It searches for that tag.
Change the jquery if you want to search for something else.
*/
var fileStackGet = "loaduser.php"; // set this to the location of the php file
var ano = 'rel="nofollow" ';
// formats reputation score kind of like on the site "31.2k", "200k"
function formatRep(r){
if ( r >= 10000000 )
r = ((r/1000000).toFixed(1)+'').replace(/(.{1})(.{5})/,"$1,$2")+"m";
else if ( r >= 100000 )
r = ((r/1000).toFixed(0)+'')+"k";
else if ( r >= 10000 )
r = ((r/1000).toFixed(1)+'').replace(/(.{1})(.{5})/,"$1,$2")+"k";
else if ( r >= 1000 )
r = (r+'').replace(/(.{1})(.{3})/,"$1,$2");
return r;
}
// shortens site name for output
// e.g. 'http://somewhere.com/some_place_on_the_site/page.php' to 'somewhere.com/some_place_on_the_sit...'
function formatSite(s,l){
if(l===undefined)l=48;
s=s.replace(/^https?:\/\//,'');
if(s.length > l )s=s.substr(0,l-3)+'...';
return s;
}
// I didn't actually finish this function if someone wants to tweak it...
// s[0] is about-me which gets cut off in 5 lines (didn't even start)
// s[1] holds links in the cut off portion
function formatAbout( a, ano ){
// this is a spaghetti hack (and a half)... I hope someone can make this more efficient
a = a.replace(/[\s]+/gim,' ') // get rid of all unneeded space right away
// since we are going to use the alt of the image (* doesn't) we are putting it on the previous line
.replace(/(?:\s*<\/?(?:br|p)(?:\s*\/)?>\s*)+((<a(\s[^>]*)?>)?<img\s[^>]*>(<\/a>)?)\s*<\/?(br|p)(\s*\/)?>\s*/gi,' $1[:p:]')
.replace(/<\/p>|<br(\s*\/)?>/gi,'[:p:]') // find all the </p> and all <br> tags to break at
.replace(/<a\s[^>]*href=('([^']*)'|"([^"]*)")[^>]*>/gi,'[:a:$2$3]') // pull out <a> tags so we don't strip them
.replace(/<\/a>/gi,'[:/a:]')
.replace(/<img\s[^>]*alt=('([^']*)'|"([^"]*)")[^>]*>/gi,'$2$3') // get the alts from the imgs
.replace(/<(li)>/gi,' ')// some might need space... not sure about other tags yet
.replace(/<[^>]*>/g,'') // strip all other tags and <>
.replace(/\[:a:([^\]]*)\]\s*/g,'<a '+ano+'href="$1">') // put the <a> tags back
.replace(/\s*\[:\/a:\]/g,'</a>')
.replace(/[\s]+/g,' ') // double check space
.split('[:p:]'); // split on the breaks
// at this point we should have only <a> tags and it's split where we need to add breaks
var len = a.length, l2, r = ['',''], n = 0, m = 0;
var i,j,s,c,t=false;
var h=0,hnum=3,hlen=18;//h is the amount of links currently in r[1], hnum is max h can get, hlen is the length of the text
for ( i=0; n < 5 && i < len; ++i ){
l2 = a[i].length;
if ( l2 < 1 ) continue;
s=0;m=0;t=false;
for ( j=0; j < l2; ++j ){ // this is probably how I should have done above...
// no real checks on <a> tag, just assuming start/end exist in order
c=a[i].charAt(j);
switch (s){
case 0:
if(c=='&'){//special char
s=1;
} else if (c=='<') {
s=2;
t=!t;
} else {
++m;
}
r[0] += c;
break;
case 1:
if(c==';'){//end special char
s=0;
++m;
}
r[0] += c;
break;
case 2:
if(c=='>'){
s=0;
}
r[0] += c;
break;
default:break;// should never end up here
};
// unsure on per line, just guessing
if ( m > 50 ){
m = 0;
++n;
}
if ( n >= 5 ){
if ( t ){
r[0] += "</a>";
j = a[i].indexOf('</a',j+1);
if ( j == -1 ) j = l2;
}
r[0] = r[0].substr(0,r[0].length-3)+"...";
break;
}
}
// reusing m and s for different purposes below here
if ( j < l2 ) {
// check if there are more <a>
j = a[i].indexOf('<a',j+1);
while ( j != -1 && j+1 < l2 && h < hnum ){
s = a[i].indexOf('>',j)+1;
m = a[i].indexOf('</a',j);
if ( s > -1 && m > -1 && s < m ){
r[1] += a[i].substring(j,s);
j=s;
s=a[i].substring(j,m);
if ( s.length > hlen ){
s = s.substr(0,hlen-3)+'...';
}
r[1] += s+"</a> ";
++h;
j = a[i].indexOf('<a',m+4);
} else {
j=-1;
}
}
}
if ( n <= 5 ){
r[0] += '<br />';
}
++n;
}
while ( i < len && h < hnum ){
j = a[i].indexOf('<a',j);
while ( j > -1 && h < hnum ){
s = a[i].indexOf('>',j)+1;
m = a[i].indexOf('</a',j);
if ( s > -1 && m > -1 && s < m ){
r[1] += a[i].substring(j,s);
j=s;
s=a[i].substring(j,m);
if ( s.length > hlen ){
s = s.substr(0,hlen-3)+'...';
}
r[1] += s+"</a> ";
++h;
j = a[i].indexOf('<a',m+4);
} else {
j=-1;
}
}
++i;
}
return r;
}
// This returns '###' from 'http://*.com/users/flair/###.png'
function getId( s ){
s = s.substr(s.lastIndexOf('/')+1);
return s.substr(0,s.indexOf('.'));
}
// returns individual css (may need to work on this)
function css( user_id, top, left, width, height ){
var w='div#u_outerwrap'+user_id;
return '<style type="text/css">'
+w+'{display:inline;margin:0;padding:0;border:none;}'
+w+' span.badge1{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7KBn0AHUAAAAIdEVYdENvbW1lbnQA9syWvwAAAFZJREFUGNNjYMABGD8c5hfk5uZaxcjI4MLAwMDw/z/Dnq9fv4Ux/j4nuRsmCAP//zPsYfxzXvI/NqOYcNnB9P8/wx50wf//GfYwff36LQxZEmY5Ax0AADG6IrHAoV3lAAAAAElFTkSuQmCC);}'
+w+' span.badge2{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7OXNEIIcAAAAIdEVYdENvbW1lbnQA9syWvwAAAEZJREFUGNO9jbENwDAMw2h9kJ96Q47MDdl8mLqkgDt4DSdBBCRoiMwcwIqIB8D2BqZqCXDyUi2rVPehs/nD9hYwq/zOucALY70ZZlPtha4AAAAASUVORK5CYII=);}'
+w+' span.badge3{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7FDabfPIAAAAIdEVYdENvbW1lbnQA9syWvwAAAFNJREFUGNO9jbENwCAQxO4e0dFkJ2agyGAZghm+y0p0CF2qSK9ItHFpFwY28L7OI6fSSVYAkORzjWZRAgDJmlPpFmWMtnuYJP9KSW5zjRbjO8cPPDYBIdBekI7gAAAAAElFTkSuQmCC);}'
+w+' span.badges{background-repeat:no-repeat;display:inline-block;height:11px;line-height:inherit;'+
'margin:0 1px 1px 3px;overflow:hidden;vertical-align:text-bottom;width:6px;}'
+w+' a img{border:none;}'
+w+' .badgecount{color:#808185;padding-left:1px;}'
+w+' div#user-menu'+user_id+'{-moz-border-bottom-colors:none;-moz-border-image:none;-moz-border-left-colors:none;'+
'-moz-border-right-colors:none;-moz-border-top-colors:none;background-color:#333333;border-color:#444444 #1C1C1C #1C1C1C;'+
'border-radius:4px 4px 4px 4px;border-right:1px solid #1C1C1C;border-style:solid;border-width:1px;'+
'box-shadow:0 2px 4px rgba(0, 0, 0, 0.5), 0 1px 0 #727272 inset;color:#E3E3E3;'+
'font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;font-size:11px;line-height:1.2;'+
'padding:10px;text-align:left;width:300px;z-index:320;}'
+w+' div.um-gravatar{float:left;margin-right:8px;height:64px;width:64px;}'
+w+' div.um-header-info a.um-user-link,'
+w+' div.um-header-info span.mod-flair{color:#e2e2e2!important;font-size:18px;}'
+w+' div.um-header-info span.mod-flair{margin-left:3px;}'
+w+' div.um-header-info div.um-flair .badgecount{color:#e2e2e2;}'
+w+' div.um-header-info div.um-flair .reputation-score{color:#e2e2e2;font-size:120%;font-weight:700;margin-right:2px;}'
+w+' div.um-about-me{clear:both;font-size:11px;margin:5px 0;overflow:hidden;}'
+w+' span.um-links a{font-size:11px;margin-right:8px;}'
+w+' a,'+w+' a:visited{color:#b4d4ec;text-decoration:none;}'
+w+' a:hover{color:#dcecf7;}'
+w+' div#user-menu-wrap'+user_id+'{position:absolute;z-index:320;position:absolute;z-index:320;'+
'top:'+top+';left:'+left+';width:'+width+';height:'+height+';}'
+'</style>';
}
// bc is the badge count and t is the type
function getBadge( bc, t ){
if ( bc > 0 ){
return '<span title="'+bc+' '+(t==1?'gold':(t==2?'silver':'bronze'))
+' badges"><span class="badge'+t+' badges"></span><span class="badgecount">'+bc+'</span></span>'
}
return '';
}
// this is the usermenu that drops down
function getUserMenu( user, ano ){
var about=formatAbout(user['about_me'],ano);
return '<div id="user-menu-wrap'+user['user_id']+'" class="user-menu-wrap" style="display:none;">'
+'<div id="user-menu'+user['user_id']+'" class="user-menu">'
+'<div class="um-header"><div class="um-gravatar"><a '+ano+'href=""><div>'
+'<img alt="gravatar image" src="http://www.gravatar.com/avatar/'+user['email_hash']
+'?s=64&d=identicon&r=PG" '+'style="width:64px;height:64px;visibility:visible;border:0 none;" />'
+'</div></a></div>'+'<div class="um-header-info">'+'<a class="um-user-link" '+ano
+'href="http://*.com/users/'+user['user_id']+'">'+user['display_name']+'</a>'
+(user['user_type']=='moderator'?'<span class="mod-flair" title="moderator">♦</span>':'')
+'<br /><div class="um-flair">'
+'<span title="reputation score '+user['reputation']+'" class="reputation-score">'
+formatRep(user['reputation'])+'</span>'
+getBadge(user['badge_counts']['gold'],1)
+getBadge(user['badge_counts']['silver'],2)
+getBadge(user['badge_counts']['bronze'],3)
+'</div>'+user['location']+'<br />'
+'<a '+ano+'href="'+user['website_url']+'">'+formatSite(user['website_url'])+'</a>'
+'</div><div class="um-about-me">'+about[0]+'</div></div>'
+'<span class="um-links">'+about[1]+'</span>'
+'</div>';
}
$(document).ready(function(){
$('img[src^="http://*.com/users/flair/"]').each(function(){
var failjson = false; // unsure if needed or works
var timg = $(this);
var user_id = getId(timg.attr("src"));
var user_menu = new Array();
$.getJSON( fileStackGet + "?user_id=" + user_id, function(user){
if( user != null && user["users"][0] != null && user["users"][0]["user_id"] != null
&& user["users"][0]["user_id"] == user_id ){
user_menu[user_id] = getUserMenu(user["users"][0],ano);
}else{
failjson = true;
}
}).success(function() {
if ( failjson ) { return; }
var pos=timg.position();
pos.h=timg.height();
pos.w=timg.width();
var p=timg.parent(); // get <a> around <img>
p.css("text-decoration","none");
p=p.wrap('<div class="u_outerwrap" id="u_outerwrap'+user_id+'" />').parent();
p.html( css(user_id,pos.top,pos.left,pos.h,pos.w) + p.html() + user_menu[user_id] );
p.hover(function(){
$('div#user-menu-wrap'+user_id)
.css("position","absolute").css("z-index",320)
.css("top",pos.top).css("left",pos.left).css("width",pos.w).css("height",pos.h)
.show()
.animate({left:'-=10',height:'183',width:'330'},500);
},
function(){
$('#user-menu-wrap'+user_id).hide();
}
);
});
});
});
the php (basically just gets user from * (if not stored and is fresh), stores in file, and spits it out) it was named "loaduser.php"
php(基本上只是从*获取用户(如果没有存储并且是新鲜的),存储在文件中,并将其吐出)它被命名为“loaduser.php”
<?php
/*
* author: craniumonempty
* php for user dropdown over user flair (designed for *, but should be easily adapted)
* to be used in conjuntion with javascript/jquery
*
* This simply gets data from site and stores in a folder. It polls the site according to $secconds_to_wait.
*
* This requires that the directory is writable. If not, then change $filename to point to a writable directory.
*/
if(!isset($_GET['user_id'])){exit;}
$u=(int)$_GET['user_id'];
// I set individual files because I was testing a few different users
$filename = dirname(__FILE__).DIRECTORY_SEPARATOR."userdata${u}.txt";
$seconds_to_wait = 1200; // >= 60
/*
http://api.*.com/1.0/usage
Polling for changes should be done sparingly in any case, and polling at a rate faster than once a minute (for semantically identical requests) is considered abusive.
*/
function getStackUserDataStore($filename,$seconds,$nocheck=false){
$send = false;
// check file for data if it is fresher than preset time
// if it is return it and send, else return false
file_exists($filename) && $send = file_get_contents($filename);
// no need to check if false, if it's at 0, something is wrong
if ( $n = strpos($send,"\n") ) {
$time = (int)substr($send,0,$n);
if ( $nocheck || time()-$time < $seconds ) {
$send = substr($send,$n+1);
} else {
$send = false;
}
}
return $send;
}
function setStackUserDataStore($filename,$data){
// no need to check for false directly, if it writes 0 bytes, something is wrong
if ( !file_put_contents($filename,time()."\n".$data) ) { return false; }
// update data for user
return true;
}
function getStackUser($userid,$filename,$seconds=120){
if( $userid <= 0 ){ die("getStackUser: user_id<=0"); }
if( $seconds < 60 ){ $seconds = 60; }
if ( !($user_data = getStackUserDataStore($filename,$seconds)) ) {
ob_start();
@readgzfile("http://api.*.com/1.1/users/".(int)$userid);
$user_data = ob_get_contents();
ob_end_clean();
if ( $user_data == '' ) { // probably can't connect, try to get datastore with no check
$user_data = getStackUserDataStore($filename,$seconds,true);
} else if ( !setStackUserDataStore($filename,$user_data) ) {
// unable to store... should do something
die("getStackUser: Unable to write data");
}
}
return $user_data;
}
if ( !($user_data = getStackUser($u,$filename,$seconds_to_wait)) ) {
// something went wrong
die("getStackUser: Unable to get user data");
}
echo $user_data;
#1
2
This is the code I have currently... I had to delete the rest to make it fit.
这是我目前的代码......我不得不删除其余部分以使其适合。
-- I cleaned up the code quite a bit, but let me know if I need to clarify something as I'm not the best at documenting.
- 我清理了相当多的代码,但是如果我需要澄清一些内容,请告诉我,因为我不是最好的文档。
This is the js that was named "so.js"
这是名为“so.js”的js
/*
* author: craniumonempty
* javascript/jquery for user dropdown over user flair for user sites (designed with *, but should be easily adapted)
* to be used in conjuntion with php
*
* Nothing to be called, it searches for all * flair (as given by website with <a><img></a>) on page
*
* This requires JQquery 1.5 or newer due to the $.getJSON().success() function call
*/
/* Minimal html to test:
<html><head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="so.js"></script>
</head><body>
<a href="http://*.com/users/540753/craniumonempty">
<img src="http://*.com/users/flair/540753.png" width="208" height="58" alt="profile for craniumonempty at Stack Overflow, Q&A for professional and enthusiast programmers" title="profile for craniumonempty at Stack Overflow, Q&A for professional and enthusiast programmers">
</a>
</body></html>
Note, jquery >= 1.5 and tag (<a><img></a>) with the * site. It searches for that tag.
Change the jquery if you want to search for something else.
*/
var fileStackGet = "loaduser.php"; // set this to the location of the php file
var ano = 'rel="nofollow" ';
// formats reputation score kind of like on the site "31.2k", "200k"
function formatRep(r){
if ( r >= 10000000 )
r = ((r/1000000).toFixed(1)+'').replace(/(.{1})(.{5})/,"$1,$2")+"m";
else if ( r >= 100000 )
r = ((r/1000).toFixed(0)+'')+"k";
else if ( r >= 10000 )
r = ((r/1000).toFixed(1)+'').replace(/(.{1})(.{5})/,"$1,$2")+"k";
else if ( r >= 1000 )
r = (r+'').replace(/(.{1})(.{3})/,"$1,$2");
return r;
}
// shortens site name for output
// e.g. 'http://somewhere.com/some_place_on_the_site/page.php' to 'somewhere.com/some_place_on_the_sit...'
function formatSite(s,l){
if(l===undefined)l=48;
s=s.replace(/^https?:\/\//,'');
if(s.length > l )s=s.substr(0,l-3)+'...';
return s;
}
// I didn't actually finish this function if someone wants to tweak it...
// s[0] is about-me which gets cut off in 5 lines (didn't even start)
// s[1] holds links in the cut off portion
function formatAbout( a, ano ){
// this is a spaghetti hack (and a half)... I hope someone can make this more efficient
a = a.replace(/[\s]+/gim,' ') // get rid of all unneeded space right away
// since we are going to use the alt of the image (* doesn't) we are putting it on the previous line
.replace(/(?:\s*<\/?(?:br|p)(?:\s*\/)?>\s*)+((<a(\s[^>]*)?>)?<img\s[^>]*>(<\/a>)?)\s*<\/?(br|p)(\s*\/)?>\s*/gi,' $1[:p:]')
.replace(/<\/p>|<br(\s*\/)?>/gi,'[:p:]') // find all the </p> and all <br> tags to break at
.replace(/<a\s[^>]*href=('([^']*)'|"([^"]*)")[^>]*>/gi,'[:a:$2$3]') // pull out <a> tags so we don't strip them
.replace(/<\/a>/gi,'[:/a:]')
.replace(/<img\s[^>]*alt=('([^']*)'|"([^"]*)")[^>]*>/gi,'$2$3') // get the alts from the imgs
.replace(/<(li)>/gi,' ')// some might need space... not sure about other tags yet
.replace(/<[^>]*>/g,'') // strip all other tags and <>
.replace(/\[:a:([^\]]*)\]\s*/g,'<a '+ano+'href="$1">') // put the <a> tags back
.replace(/\s*\[:\/a:\]/g,'</a>')
.replace(/[\s]+/g,' ') // double check space
.split('[:p:]'); // split on the breaks
// at this point we should have only <a> tags and it's split where we need to add breaks
var len = a.length, l2, r = ['',''], n = 0, m = 0;
var i,j,s,c,t=false;
var h=0,hnum=3,hlen=18;//h is the amount of links currently in r[1], hnum is max h can get, hlen is the length of the text
for ( i=0; n < 5 && i < len; ++i ){
l2 = a[i].length;
if ( l2 < 1 ) continue;
s=0;m=0;t=false;
for ( j=0; j < l2; ++j ){ // this is probably how I should have done above...
// no real checks on <a> tag, just assuming start/end exist in order
c=a[i].charAt(j);
switch (s){
case 0:
if(c=='&'){//special char
s=1;
} else if (c=='<') {
s=2;
t=!t;
} else {
++m;
}
r[0] += c;
break;
case 1:
if(c==';'){//end special char
s=0;
++m;
}
r[0] += c;
break;
case 2:
if(c=='>'){
s=0;
}
r[0] += c;
break;
default:break;// should never end up here
};
// unsure on per line, just guessing
if ( m > 50 ){
m = 0;
++n;
}
if ( n >= 5 ){
if ( t ){
r[0] += "</a>";
j = a[i].indexOf('</a',j+1);
if ( j == -1 ) j = l2;
}
r[0] = r[0].substr(0,r[0].length-3)+"...";
break;
}
}
// reusing m and s for different purposes below here
if ( j < l2 ) {
// check if there are more <a>
j = a[i].indexOf('<a',j+1);
while ( j != -1 && j+1 < l2 && h < hnum ){
s = a[i].indexOf('>',j)+1;
m = a[i].indexOf('</a',j);
if ( s > -1 && m > -1 && s < m ){
r[1] += a[i].substring(j,s);
j=s;
s=a[i].substring(j,m);
if ( s.length > hlen ){
s = s.substr(0,hlen-3)+'...';
}
r[1] += s+"</a> ";
++h;
j = a[i].indexOf('<a',m+4);
} else {
j=-1;
}
}
}
if ( n <= 5 ){
r[0] += '<br />';
}
++n;
}
while ( i < len && h < hnum ){
j = a[i].indexOf('<a',j);
while ( j > -1 && h < hnum ){
s = a[i].indexOf('>',j)+1;
m = a[i].indexOf('</a',j);
if ( s > -1 && m > -1 && s < m ){
r[1] += a[i].substring(j,s);
j=s;
s=a[i].substring(j,m);
if ( s.length > hlen ){
s = s.substr(0,hlen-3)+'...';
}
r[1] += s+"</a> ";
++h;
j = a[i].indexOf('<a',m+4);
} else {
j=-1;
}
}
++i;
}
return r;
}
// This returns '###' from 'http://*.com/users/flair/###.png'
function getId( s ){
s = s.substr(s.lastIndexOf('/')+1);
return s.substr(0,s.indexOf('.'));
}
// returns individual css (may need to work on this)
function css( user_id, top, left, width, height ){
var w='div#u_outerwrap'+user_id;
return '<style type="text/css">'
+w+'{display:inline;margin:0;padding:0;border:none;}'
+w+' span.badge1{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7KBn0AHUAAAAIdEVYdENvbW1lbnQA9syWvwAAAFZJREFUGNNjYMABGD8c5hfk5uZaxcjI4MLAwMDw/z/Dnq9fv4Ux/j4nuRsmCAP//zPsYfxzXvI/NqOYcNnB9P8/wx50wf//GfYwff36LQxZEmY5Ax0AADG6IrHAoV3lAAAAAElFTkSuQmCC);}'
+w+' span.badge2{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7OXNEIIcAAAAIdEVYdENvbW1lbnQA9syWvwAAAEZJREFUGNO9jbENwDAMw2h9kJ96Q47MDdl8mLqkgDt4DSdBBCRoiMwcwIqIB8D2BqZqCXDyUi2rVPehs/nD9hYwq/zOucALY70ZZlPtha4AAAAASUVORK5CYII=);}'
+w+' span.badge3{background:url(data:image/png;base64,'+'iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sMCRA7FDabfPIAAAAIdEVYdENvbW1lbnQA9syWvwAAAFNJREFUGNO9jbENwCAQxO4e0dFkJ2agyGAZghm+y0p0CF2qSK9ItHFpFwY28L7OI6fSSVYAkORzjWZRAgDJmlPpFmWMtnuYJP9KSW5zjRbjO8cPPDYBIdBekI7gAAAAAElFTkSuQmCC);}'
+w+' span.badges{background-repeat:no-repeat;display:inline-block;height:11px;line-height:inherit;'+
'margin:0 1px 1px 3px;overflow:hidden;vertical-align:text-bottom;width:6px;}'
+w+' a img{border:none;}'
+w+' .badgecount{color:#808185;padding-left:1px;}'
+w+' div#user-menu'+user_id+'{-moz-border-bottom-colors:none;-moz-border-image:none;-moz-border-left-colors:none;'+
'-moz-border-right-colors:none;-moz-border-top-colors:none;background-color:#333333;border-color:#444444 #1C1C1C #1C1C1C;'+
'border-radius:4px 4px 4px 4px;border-right:1px solid #1C1C1C;border-style:solid;border-width:1px;'+
'box-shadow:0 2px 4px rgba(0, 0, 0, 0.5), 0 1px 0 #727272 inset;color:#E3E3E3;'+
'font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;font-size:11px;line-height:1.2;'+
'padding:10px;text-align:left;width:300px;z-index:320;}'
+w+' div.um-gravatar{float:left;margin-right:8px;height:64px;width:64px;}'
+w+' div.um-header-info a.um-user-link,'
+w+' div.um-header-info span.mod-flair{color:#e2e2e2!important;font-size:18px;}'
+w+' div.um-header-info span.mod-flair{margin-left:3px;}'
+w+' div.um-header-info div.um-flair .badgecount{color:#e2e2e2;}'
+w+' div.um-header-info div.um-flair .reputation-score{color:#e2e2e2;font-size:120%;font-weight:700;margin-right:2px;}'
+w+' div.um-about-me{clear:both;font-size:11px;margin:5px 0;overflow:hidden;}'
+w+' span.um-links a{font-size:11px;margin-right:8px;}'
+w+' a,'+w+' a:visited{color:#b4d4ec;text-decoration:none;}'
+w+' a:hover{color:#dcecf7;}'
+w+' div#user-menu-wrap'+user_id+'{position:absolute;z-index:320;position:absolute;z-index:320;'+
'top:'+top+';left:'+left+';width:'+width+';height:'+height+';}'
+'</style>';
}
// bc is the badge count and t is the type
function getBadge( bc, t ){
if ( bc > 0 ){
return '<span title="'+bc+' '+(t==1?'gold':(t==2?'silver':'bronze'))
+' badges"><span class="badge'+t+' badges"></span><span class="badgecount">'+bc+'</span></span>'
}
return '';
}
// this is the usermenu that drops down
function getUserMenu( user, ano ){
var about=formatAbout(user['about_me'],ano);
return '<div id="user-menu-wrap'+user['user_id']+'" class="user-menu-wrap" style="display:none;">'
+'<div id="user-menu'+user['user_id']+'" class="user-menu">'
+'<div class="um-header"><div class="um-gravatar"><a '+ano+'href=""><div>'
+'<img alt="gravatar image" src="http://www.gravatar.com/avatar/'+user['email_hash']
+'?s=64&d=identicon&r=PG" '+'style="width:64px;height:64px;visibility:visible;border:0 none;" />'
+'</div></a></div>'+'<div class="um-header-info">'+'<a class="um-user-link" '+ano
+'href="http://*.com/users/'+user['user_id']+'">'+user['display_name']+'</a>'
+(user['user_type']=='moderator'?'<span class="mod-flair" title="moderator">♦</span>':'')
+'<br /><div class="um-flair">'
+'<span title="reputation score '+user['reputation']+'" class="reputation-score">'
+formatRep(user['reputation'])+'</span>'
+getBadge(user['badge_counts']['gold'],1)
+getBadge(user['badge_counts']['silver'],2)
+getBadge(user['badge_counts']['bronze'],3)
+'</div>'+user['location']+'<br />'
+'<a '+ano+'href="'+user['website_url']+'">'+formatSite(user['website_url'])+'</a>'
+'</div><div class="um-about-me">'+about[0]+'</div></div>'
+'<span class="um-links">'+about[1]+'</span>'
+'</div>';
}
$(document).ready(function(){
$('img[src^="http://*.com/users/flair/"]').each(function(){
var failjson = false; // unsure if needed or works
var timg = $(this);
var user_id = getId(timg.attr("src"));
var user_menu = new Array();
$.getJSON( fileStackGet + "?user_id=" + user_id, function(user){
if( user != null && user["users"][0] != null && user["users"][0]["user_id"] != null
&& user["users"][0]["user_id"] == user_id ){
user_menu[user_id] = getUserMenu(user["users"][0],ano);
}else{
failjson = true;
}
}).success(function() {
if ( failjson ) { return; }
var pos=timg.position();
pos.h=timg.height();
pos.w=timg.width();
var p=timg.parent(); // get <a> around <img>
p.css("text-decoration","none");
p=p.wrap('<div class="u_outerwrap" id="u_outerwrap'+user_id+'" />').parent();
p.html( css(user_id,pos.top,pos.left,pos.h,pos.w) + p.html() + user_menu[user_id] );
p.hover(function(){
$('div#user-menu-wrap'+user_id)
.css("position","absolute").css("z-index",320)
.css("top",pos.top).css("left",pos.left).css("width",pos.w).css("height",pos.h)
.show()
.animate({left:'-=10',height:'183',width:'330'},500);
},
function(){
$('#user-menu-wrap'+user_id).hide();
}
);
});
});
});
the php (basically just gets user from * (if not stored and is fresh), stores in file, and spits it out) it was named "loaduser.php"
php(基本上只是从*获取用户(如果没有存储并且是新鲜的),存储在文件中,并将其吐出)它被命名为“loaduser.php”
<?php
/*
* author: craniumonempty
* php for user dropdown over user flair (designed for *, but should be easily adapted)
* to be used in conjuntion with javascript/jquery
*
* This simply gets data from site and stores in a folder. It polls the site according to $secconds_to_wait.
*
* This requires that the directory is writable. If not, then change $filename to point to a writable directory.
*/
if(!isset($_GET['user_id'])){exit;}
$u=(int)$_GET['user_id'];
// I set individual files because I was testing a few different users
$filename = dirname(__FILE__).DIRECTORY_SEPARATOR."userdata${u}.txt";
$seconds_to_wait = 1200; // >= 60
/*
http://api.*.com/1.0/usage
Polling for changes should be done sparingly in any case, and polling at a rate faster than once a minute (for semantically identical requests) is considered abusive.
*/
function getStackUserDataStore($filename,$seconds,$nocheck=false){
$send = false;
// check file for data if it is fresher than preset time
// if it is return it and send, else return false
file_exists($filename) && $send = file_get_contents($filename);
// no need to check if false, if it's at 0, something is wrong
if ( $n = strpos($send,"\n") ) {
$time = (int)substr($send,0,$n);
if ( $nocheck || time()-$time < $seconds ) {
$send = substr($send,$n+1);
} else {
$send = false;
}
}
return $send;
}
function setStackUserDataStore($filename,$data){
// no need to check for false directly, if it writes 0 bytes, something is wrong
if ( !file_put_contents($filename,time()."\n".$data) ) { return false; }
// update data for user
return true;
}
function getStackUser($userid,$filename,$seconds=120){
if( $userid <= 0 ){ die("getStackUser: user_id<=0"); }
if( $seconds < 60 ){ $seconds = 60; }
if ( !($user_data = getStackUserDataStore($filename,$seconds)) ) {
ob_start();
@readgzfile("http://api.*.com/1.1/users/".(int)$userid);
$user_data = ob_get_contents();
ob_end_clean();
if ( $user_data == '' ) { // probably can't connect, try to get datastore with no check
$user_data = getStackUserDataStore($filename,$seconds,true);
} else if ( !setStackUserDataStore($filename,$user_data) ) {
// unable to store... should do something
die("getStackUser: Unable to write data");
}
}
return $user_data;
}
if ( !($user_data = getStackUser($u,$filename,$seconds_to_wait)) ) {
// something went wrong
die("getStackUser: Unable to get user data");
}
echo $user_data;