如何让我的网站显示扩展的用户卡?

时间:2022-10-19 22:47:01

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&amp;A for professional and enthusiast programmers" title="profile for Mr.32 at Stack Overflow, Q&amp;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&amp;A for professional and enthusiast programmers" title="profile for craniumonempty at Stack Overflow, Q&amp;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&amp;d=identicon&amp;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">&#9830;</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&amp;A for professional and enthusiast programmers" title="profile for craniumonempty at Stack Overflow, Q&amp;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&amp;d=identicon&amp;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">&#9830;</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;