Advertisement
Guest User

Untitled

a guest
Aug 26th, 2014
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name TF2 Profile Script
  3. // @namespace tfprofile
  4. // @version 1.1.3
  5. // @description Mouse over profile links (steamcommunity/etf2l/wireplay/teamfortress.tv) to get links their profiles on otherwebsites
  6. // @downloadURL https://github.com/CasualX/UserScripts/raw/master/tfprofile.user.js
  7. // @updateURL https://github.com/CasualX/UserScripts/raw/master/tfprofile.user.js
  8. // @include http://*
  9. // @include https://*
  10. // @grant GM_xmlhttpRequest
  11. // @run-at document-end
  12. // ==/UserScript==
  13.  
  14. // Base conversion of arbitrary precision integers
  15. // Minified from http://danvk.org/hex2dec.html
  16. function convertBase(e,t,n){function r(e,t,n){var r=[];var i=Math.max(e.length,t.length);var s=0;var o=0;while(o<i||s){var u=o<e.length?e[o]:0;var a=o<t.length?t[o]:0;var f=s+u+a;r.push(f%n);s=Math.floor(f/n);o++}return r}function i(e,t,n){if(e<0)return null;if(e==0)return[];var i=[];var s=t;while(true){if(e&1){i=r(i,s,n)}e=e>>1;if(e===0)break;s=r(s,s,n)}return i}function s(e,t){var n=e.split("");var r=[];for(var i=n.length-1;i>=0;i--){var s=parseInt(n[i],t);if(isNaN(s))return null;r.push(s)}return r}var o=s(e,t);if(o===null)return null;var u=[];var a=[1];for(var f=0;f<o.length;f++){if(o[f]){u=r(u,i(o[f],a,n),n)}a=i(t,a,n)}var l="";for(var f=u.length-1;f>=0;f--){l+=u[f].toString(n)}return l}
  17. // Googled this for Chrome compat, minified
  18. function addStyle(e){var t=document.createElement("style");t.type="text/css";t.appendChild(document.createTextNode(e));document.getElementsByTagName("head")[0].appendChild(t)}
  19.  
  20. //----------------------------------------------------------------
  21. // Steam ID container
  22. function CSteamID()
  23. {
  24. this.unAccountID = 0;
  25. this.unAccountInstance = 0;
  26. this.EAccountType = CSteamID.EAccountType.k_EAccountTypeInvalid;
  27. this.EUniverse = CSteamID.EUniverse.k_EUniverseInvalid;
  28. }
  29. CSteamID.prototype.setID = function( sid, type, uni )
  30. {
  31. this.unAccountID = sid;
  32. this.unAccountInstance = 1;
  33. this.EAccountType = type || CSteamID.EAccountType.k_EAccountTypeIndividual;
  34. this.EUniverse = uni || CSteamID.EUniverse.k_EUniversePublic;
  35. }
  36. CSteamID.prototype.setID64 = function( id )
  37. {
  38. var hex = "0000000000000000" + convertBase( id, 10, 16 );
  39.  
  40. // Break down the (hexadecimal) community id
  41. this.unAccountID = parseInt(hex.substr(-8,8),16);
  42. this.unAccountInstance = parseInt(hex.substr(-13,5),16);
  43. this.EAccountType = parseInt(hex.substr(-14,1),16);
  44. this.EUniverse = parseInt(hex.substr(-16,2),16);
  45. }
  46. CSteamID.prototype.render = function()
  47. {
  48. // Old style U:x:y format
  49. return "U:" + (this.unAccountID%2) + ":" + (this.unAccountID>>1);
  50. }
  51. CSteamID.prototype.toString = function()
  52. {
  53. function s( num, len )
  54. {
  55. var str = num.toString(16);
  56. return "0000000000000000".substr(0,len-str.length)+str;
  57. }
  58. var hex = s(this.EUniverse,2) + s(this.EAccountType,1) + s(this.unAccountInstance,5) + s(this.unAccountID,8);
  59. return convertBase( hex, 16, 10 );
  60. }
  61. CSteamID.EUniverse = { k_EUniverseInvalid:0, k_EUniversePublic:1, k_EUniverseBeta:2, k_EUniverseInternal:3, k_EUniverseDev:4, k_EUniverseRC:5, k_EUniverseMax:6 };
  62. CSteamID.EAccountType = { k_EAccountTypeInvalid:0, k_EAccountTypeIndividual:1, k_EAccountTypeMultiseat:2, k_EAccountTypeGameServer:3, k_EAccountTypeAnonGameServer:4, k_EAccountTypePending:5, k_EAccountTypeContentServer:6, k_EAccountTypeClan:7, k_EAccountTypeChat:8, k_EAccountTypeP2PSuperSeeder:9, k_EAccountTypeMax:10 };
  63. CSteamID.parse = function( str )
  64. {
  65. var re, sid = null;
  66. // Old SteamID with and without prefix in any of three exciting flavours
  67. if ( re = /^(?:STEAM_|Steam_|steam_)?0\:([01])\:(\d+)$/.exec( str ) )
  68. {
  69. sid = new CSteamID();
  70. sid.setID( parseInt(re[2])*2 + parseInt(re[1]) );
  71. }
  72. // New SteamID with and without square brackets
  73. else if ( re = /^\[?U:1:(\d+)\]?$/.exec( str ) )
  74. {
  75. sid = new CSteamID();
  76. sid.setID( parseInt(re[1]) );
  77. }
  78. // SteamID64
  79. else if ( re = /^\d+$/.exec( str ) )
  80. {
  81. sid = new CSteamID();
  82. sid.setID64( str );
  83. }
  84. return sid;
  85. }
  86. //----------------------------------------------------------------
  87.  
  88. // Find profiles with search engine because they don't have an API...
  89. function searchEngine( site, title, content, fn )
  90. {
  91. function search( engine )
  92. {
  93. GM_xmlhttpRequest( {
  94. method: "GET",
  95. url: engine.qurl + encodeURIComponent( 'site:'+site+' title:"'+title+'" "'+content+'"' ),
  96. onload: function( resp ) { match( resp.responseText, engine ); },
  97. onerror: function( resp ) { match( "", engine ); }
  98. } );
  99. }
  100. function match( text, engine )
  101. {
  102. var r;
  103. while ( r = engine.regex.exec( text ) )
  104. {
  105. // Found a valid result
  106. if ( r[1].indexOf(site)>=0 )
  107. return fn( r );
  108. }
  109. // Not found, try another search engine
  110. if ( engine.next ) search( engine.next );
  111. // Tried all engines, nothing found
  112. else fn( false );
  113. }
  114. var engines = {
  115. qurl: "https://ixquick.com/do/search?q=",
  116. regex: /<a href='([^']*)' id='title_\d'/,
  117. next: {
  118. qurl: "https://startpage.com/do/search?q=",
  119. regex: /<a href='([^']*)' id='title_\d'/,
  120. }
  121. };
  122. search( engines );
  123. }
  124.  
  125. //----------------------------------------------------------------
  126. // Websites supported
  127. //----------------------------------------------------------------
  128. // Each website may have these 3 functions:
  129. // match: Given an url return a non false value if you can handle this profile link
  130. // source: Source the player's steamid from this profile url, directly called after match with its returned value (eg, regex result). Callback player.initialize with the steamid on success.
  131. // query: Find out given the steamid if this player has a profile on this website. Callback player.addLink with the url and description on success.
  132.  
  133. function siteSetLink( p, url, desc, html )
  134. {
  135. var a = document.createElement('a');
  136. a.href = url;
  137. a.target = "_blank";
  138. if ( html ) a.innerHTML = html;
  139. var text = document.createTextNode(desc);
  140. if ( a.firstChild ) a.insertBefore( text, a.firstChild );
  141. else a.appendChild( text );
  142. p.innerHTML = '';
  143. p.appendChild( a );
  144. p.className = 'TFProfile_Done';
  145. }
  146. function siteSetMissing( p )
  147. {
  148. p.className = 'TFProfile_Missing';
  149. // Hide the parent article if it only has missing links...
  150. if ( p.parentNode.children.length==p.parentNode.querySelectorAll(".TFProfile_Missing").length )
  151. p.parentNode.parentNode.removeChild( p.parentNode );
  152. }
  153.  
  154. var sites = {
  155. // Steam community support
  156. "steamcommunity.com": {
  157. group: "steam",
  158. match: function( url ) { return /^https?\:\/\/steamcommunity\.com\/(?:profiles|id)\/[^\/]*\/?$/.exec(url); },
  159. source: function( re, player )
  160. {
  161. GM_xmlhttpRequest( {
  162. method: "GET",
  163. url: re[0] + "?xml=1",
  164. onload: function( resp )
  165. {
  166. var parser = new DOMParser();
  167. var doc = parser.parseFromString( resp.responseText, "text/xml" ).documentElement;
  168. var str = doc.querySelector( "steamID64" ).textContent;
  169. player.initialize( CSteamID.parse( str ) );
  170. },
  171. onerror: function( resp )
  172. {
  173. player.error( resp.responseText );
  174. }
  175. } );
  176. },
  177. query: function( sid, player, el )
  178. {
  179. el.textContent = 'steamcommunity.com';
  180.  
  181. var commid = sid.toString();
  182. GM_xmlhttpRequest( {
  183. method: "GET",
  184. url: "https://steamcommunity.com/profiles/"+commid+"?xml=1",
  185. onload: function( resp )
  186. {
  187. var parser = new DOMParser();
  188. doc = parser.parseFromString( resp.responseText, "text/xml" ).documentElement;
  189.  
  190. // Profiles that haven't been set up do not have a name, in this case, steamID will be empty
  191. var desc = "Steam Community", name = doc.querySelector("steamID"), online = doc.querySelector("onlineState");
  192. if ( name && name.textContent ) desc += " ("+name.textContent+")";
  193. siteSetLink( el, "https://steamcommunity.com/profiles/"+commid, desc, online?'<span style="padding-left:5px;font-size:xx-small;">'+online.textContent+'</span>':undefined );
  194.  
  195. var gameIP = doc.querySelector("inGameServerIP");
  196. var gameName = doc.querySelector("inGameInfo>gameName")
  197. var gameJoin = doc.querySelector("inGameInfo>gameJoinLink");
  198. if ( gameIP && gameIP.textContent && gameName && gameName.textContent && gameJoin && gameJoin.textContent )
  199. {
  200. var a = document.createElement('a');
  201. a.href = gameJoin.textContent;
  202. a.innerHTML = "In-Game: "+gameName.textContent;
  203. el.appendChild( a );
  204. }
  205. }
  206. } );
  207. }
  208. },
  209. // ETF2L Support
  210. "etf2l.org": {
  211. group: "comptf2",
  212. match: function( url ) { return /^http\:\/\/etf2l.org\/forum\/user\/(\d+)\/?$/.exec(url); },
  213. source: function( re, player )
  214. {
  215. GM_xmlhttpRequest( {
  216. method: "GET",
  217. url: "http://etf2l.org/feed/player/?id=" + re[1],
  218. onload: function( resp )
  219. {
  220. var parser = new DOMParser();
  221. var doc = parser.parseFromString( resp.responseText, "text/xml" ).documentElement;
  222. var str = doc.querySelector( "player" );
  223. player.initialize( CSteamID.parse( str ? str.getAttribute("steamid") : "" ) );
  224. },
  225. onerror: function( resp )
  226. {
  227. player.error( resp.responseText );
  228. }
  229. } );
  230. },
  231. query: function( sid, player, el )
  232. {
  233. el.textContent = 'etf2l.org';
  234.  
  235. GM_xmlhttpRequest( {
  236. method: "GET",
  237. url: "http://etf2l.org/feed/player/?steamid=" + sid.render(),
  238. onload: function( resp )
  239. {
  240. try {
  241. var parser = new DOMParser();
  242. var doc = parser.parseFromString( resp.responseText, "text/xml" ).documentElement;
  243. var id = doc.querySelector("player").getAttribute("id");
  244. var name = doc.querySelector("displayname").textContent;
  245. siteSetLink( el, "http://etf2l.org/forum/user/"+id+"/", "ETF2L Profile ("+name+")" );
  246. } catch(e) {
  247. siteSetMissing( el );
  248. }
  249. }
  250. } );
  251. }
  252. },
  253. // Wireplay TF2 League
  254. "tf2.wireplay.co.uk": {
  255. group: "comptf2",
  256. match: function( url ) { return /^https?\:\/\/tf2\.wireplay\.co\.uk\/.*?index\.php\?pg=profile\&action=viewprofile\&aid=(\d+)/.exec(url); },
  257. source: function( re, player )
  258. {
  259. GM_xmlhttpRequest( {
  260. method: "GET",
  261. url: re[0],
  262. onload: function( resp )
  263. {
  264. var r = /<td align=left>(U\:[01]\:\d+)<\/td>/.exec(resp.responseText);
  265. player.initialize( CSteamID.parse( r?r[1]:"" ) );
  266. },
  267. onerror: function( resp )
  268. {
  269. player.error( resp.responseText );
  270. }
  271. } );
  272. },
  273. query: function( sid, player, el )
  274. {
  275. el.textContent = 'tf2.wireplay.co.uk';
  276.  
  277. GM_xmlhttpRequest( {
  278. method: "POST",
  279. url: "http://tf2.wireplay.co.uk/index.php?pg=search",
  280. data: "clantag=false&clanname=false&playername=false&steamid=true&searchterm=" + encodeURIComponent(sid.render()),
  281. headers: { "Content-Type": "application/x-www-form-urlencoded" },
  282. onload: function( resp )
  283. {
  284. try {
  285. var r = /<td><a href="(index.php\?pg=profile\&action=viewprofile\&aid=\d+)">([^<]*)<\/a><\/td>/.exec(resp.responseText);
  286. siteSetLink( el, "http://tf2.wireplay.co.uk/"+r[1], "Wireplay Profile ("+r[2]+")" );
  287. } catch(e) {
  288. siteSetMissing( el );
  289. }
  290. }
  291. } );
  292. }
  293. },
  294. // UGC League
  295. "ugcleague.com": {
  296. group: "comptf2",
  297. match: function( url ) { return /^https?\:\/\/www.ugcleague.com\/players_page\.cfm\?player_id=(\d+)$/.exec(url); },
  298. source: function( re, player ) { player.initialize( CSteamID.parse( re[1] ) ); },
  299. query: function( sid, player, el )
  300. {
  301. el.textContent = 'ugcleague.com';
  302.  
  303. // Assumption: Just check if the player's steamid is on the page, that means he's played in a team.
  304. // FIXME! Use their player search page instead? http://www.ugcleague.com/playersearch.cfm
  305. GM_xmlhttpRequest( {
  306. method: "GET",
  307. url: "http://www.ugcleague.com/players_page.cfm?player_id="+sid.toString(),
  308. onload: function( resp )
  309. {
  310. if ( resp.responseText.indexOf( "<td>"+sid.render().substr(6)+"</td>" )>=0 )
  311. siteSetLink( el, "http://www.ugcleague.com/players_page.cfm?player_id="+sid.toString(), "UGC League Profile" );
  312. else
  313. siteSetMissing( el );
  314. }
  315. } );
  316. }
  317. },
  318. // TF2Lobby.com
  319. "tf2lobby.com": {
  320. group: "lobby",
  321. match: function( url ) { return /^http\:\/\/(?:www.)?tf2lobby\.com\/profile\?(f?id)=(\d+)$/.exec(url); },
  322. source: function( re, player )
  323. {
  324. if ( re[1]==='fid' )
  325. {
  326. player.initialize( CSteamID.parse( re[2] ) );
  327. return;
  328. }
  329.  
  330. GM_xmlhttpRequest( {
  331. method: "GET",
  332. url: "http://www.tf2lobby.com/profile?id="+re[2],
  333. onload: function( resp )
  334. {
  335. var dom = new DOMParser(), doc, el, sid;
  336. if ( ( doc = parser.parseFromString( resp.responseText, "text/xml" ).documentElement ) &&
  337. ( el = doc.querySelector("#otherSites>ul>li>a") ) )
  338. {
  339. sid = CSteamID.parse( /\d+/.exec( el.href )[0] );
  340. }
  341. player.initialize( sid );
  342. },
  343. onerror: function( resp )
  344. {
  345. player.error( resp.responseText );
  346. }
  347. } );
  348. },
  349. query: function( sid, player, el )
  350. {
  351. el.textContent = 'tf2lobby.com';
  352.  
  353. GM_xmlhttpRequest( {
  354. method: "GET",
  355. url: "http://www.tf2lobby.com/profile?fid="+sid.toString(),
  356. onload: function( resp )
  357. {
  358. try {
  359. var dom = new DOMParser();
  360. var doc = dom.parseFromString( resp.responseText, "text/html" ).documentElement;
  361. var name = ( doc.querySelector("#otherSites") && doc.querySelector("#player p") ).textContent;
  362. siteSetLink( el, "http://www.tf2lobby.com/profile?fid="+sid.toString(), "TF2Lobby Profile ("+name+")" );
  363. } catch(e) {
  364. siteSetMissing( el );
  365. }
  366. }
  367. } );
  368. }
  369. },
  370. // TeamFortress.tv profiles (barely works...)
  371. "teamfortress.tv": {
  372. group: "forum",
  373. match: function( url ) { return /^https?\:\/\/teamfortress\.tv\/profile\/user\/[^\/]*\/?$/.exec(url); },
  374. source: function( re, player )
  375. {
  376. GM_xmlhttpRequest( {
  377. method: "GET",
  378. url: re[0],
  379. onload: function( resp )
  380. {
  381. var r = /(U\:[01]\:\d+)/.exec( resp.responseText );
  382. player.initialize( CSteamID.parse( r?r[1]:0 ) );
  383. },
  384. onerror: function( resp )
  385. {
  386. player.error( resp.responseText );
  387. }
  388. } );
  389. },
  390. query: function( sid, player, el )
  391. {
  392. el.textContent = 'teamfortress.tv';
  393.  
  394. // Cannot query by steamid...
  395. searchEngine( "teamfortress.tv", "Profile", sid.render(), function(r) {
  396. try {
  397. var url = r[1];
  398. var name = /profile\/user\/(.*?)\/?$/.exec(url)[1];
  399. siteSetLink( el, url, "TeamFortress.tv ("+name+")" );
  400. } catch(e) {
  401. siteSetMissing( el );
  402. }
  403. } );
  404. }
  405. },
  406. // logs.tf
  407. "logs.tf": {
  408. group: "stats",
  409. match: function( url ) { return /^https?\:\/\/(?:www.)?logs\.tf\/profile\/(\d+)\/?$/.exec(url); },
  410. source: function( re, player ) { player.initialize( CSteamID.parse( re[1] ) ); },
  411. query: function( sid, player, el )
  412. {
  413. el.textContent = 'logs.tf';
  414.  
  415. GM_xmlhttpRequest( {
  416. method: "GET",
  417. url: "http://logs.tf/profile/"+sid.toString(),
  418. onload: function( resp )
  419. {
  420. if ( !(/<h5>None found\.<\/h5>/.test(resp.responseText)) )
  421. siteSetLink( el, "http://logs.tf/profile/"+sid.toString(), "Logs.tf Profile" );
  422. else
  423. siteSetMissing( el );
  424. }
  425. } );
  426. }
  427. },
  428. // SizzlingStats.com (FIXME! Figure out their query api)
  429. "sizzlingstats.com": {
  430. group: "stats",
  431. match: function( url ) { return /^https?\:\/\/(?:www.)?sizzlingstats\.com\/player\/(\d+)\/?$/.exec(url); },
  432. source: function( re, player ) { player.initialize( CSteamID.parse( re[1] ) ); },
  433. query: function( sid, player ) { return false; }
  434. },
  435. // TF2Logs.com (does anyone still use this?)
  436. "tf2logs.com": {
  437. group: "stats",
  438. match: function( url ) { return /^https?\:\/\/(?:www.)?tf2logs\.com\/players\/(\d+)\/?$/.exec(url); },
  439. source: function( re, player ) { player.initialize( CSteamID.parse( re[1] ) ); },
  440. query: function( sid, player, el )
  441. {
  442. el.textContent = 'tf2logs.com';
  443.  
  444. GM_xmlhttpRequest( {
  445. method: "GET",
  446. url: "http://tf2logs.com/players/"+sid.toString(),
  447. onload: function( resp )
  448. {
  449. var re = /<meta name="title" content="([^>]*?) - TF2Logs.com" \/>/.exec(resp.responseText);
  450. if ( re && re[1]!='Welcome' )
  451. siteSetLink( el, "http://tf2logs.com/players/"+sid.toString(), "TF2Logs.com Profile" );
  452. else
  453. siteSetMissing( el );
  454. }
  455. } );
  456. }
  457. },
  458. };
  459.  
  460. //----------------------------------------------------------------
  461. // A link resource
  462. //----------------------------------------------------------------
  463. function linkPlayer( a )
  464. {
  465. this.anchor = a;
  466.  
  467. // Generate html
  468. var div = document.createElement('div');
  469. this.div = div;
  470. div.classList.add( 'TFProfile' );
  471. div.innerHTML = '<p>Pending...</p>';
  472. }
  473. // Initialize from a steamid
  474. linkPlayer.prototype.initialize = function( sid )
  475. {
  476. if ( sid )
  477. {
  478. // Show steam id
  479. var span = this.div.querySelector("p");
  480. span.innerHTML = '';
  481. span.appendChild( document.createTextNode( sid.render() ) );
  482. // Collect information about other websites
  483. for ( var it in sites )
  484. {
  485. var site = sites[it];
  486.  
  487. // Find the group this belongs in
  488. var group = this.div.querySelector("article.TFProfile_"+site.group);
  489. if ( !group )
  490. {
  491. group = document.createElement('article');
  492. group.className = "TFProfile_"+site.group;
  493. this.div.appendChild( group );
  494. }
  495.  
  496. var p = document.createElement('p');
  497. p.className = 'TFProfile_Pending';
  498.  
  499. if ( site.query( sid, this, p )!==false )
  500. {
  501. group.appendChild( p );
  502. }
  503. }
  504. }
  505. else
  506. {
  507. this.error( "Invalid SteamID!" );
  508. }
  509. }
  510. // Error happened
  511. linkPlayer.prototype.error = function( desc )
  512. {
  513. var p = this.div.querySelector("p");
  514. p.innerHTML = '';
  515. p.appendChild( document.createTextNode( 'Error! ' + desc ) );
  516. }
  517. // Delay the query on mouse over
  518. linkPlayer.prototype.source = function( a, re, site )
  519. {
  520. this.show( a, function() {
  521. if ( !this.sourced )
  522. {
  523. this.sourced = true;
  524. site.source( re, this );
  525. }
  526. } );
  527. }
  528. // Show the UI, delay loading as needed
  529. linkPlayer.prototype.show = function( a, fn )
  530. {
  531. var self = this;
  532. function hover()
  533. {
  534. // Begin sourcing
  535. fn.call( self );
  536. // Show our overlay only
  537. Array.prototype.forEach.call( document.querySelectorAll(".TFProfile"), function(div) { div.style.display="none"; } );
  538. clear();
  539. // Compute position of the tooltip
  540. var r = a.getBoundingClientRect();
  541. var bottom = r.bottom + ( document.documentElement.scrollTop || document.body.scrollTop );
  542. var left = r.left + ( document.documentElement.scrollLeft || document.body.scrollLeft );
  543. self.div.style.top = bottom + "px";
  544. self.div.style.left = left + "px";
  545. // Show it
  546. self.div.style.display = "block";
  547. document.body.appendChild( self.div );
  548. }
  549. function clear()
  550. {
  551. if ( self.timer )
  552. {
  553. window.clearTimeout( self.timer );
  554. self.timer = false;
  555. }
  556. }
  557. function timer( fn, ms )
  558. {
  559. clear();
  560. self.timer = window.setTimeout( fn, ms );
  561. }
  562. function leave()
  563. {
  564. self.div.style.display = "none";
  565. clear();
  566. }
  567. function related( parent, child )
  568. {
  569. return !( !child || ( child!==parent && !parent.contains( child ) ) );
  570. }
  571. a.addEventListener( 'mouseover', function(e) { timer( hover, 500 ); }, false );
  572. a.addEventListener( 'mouseout', function(e) { if ( !related(this,e.relatedTarget) ) timer( leave, 500 ); }, false );
  573. this.div.addEventListener( 'mouseover', clear, false );
  574. this.div.addEventListener( 'mouseout', function(e) { if ( !related(this,e.relatedTarget ) ) timer( leave, 200 ); }, false );
  575.  
  576. // Work around for mouseleave not working for chrome...
  577. var img = document.createElement('img');
  578. img.alt = "x";
  579. //img.src = "data:image/gif;base64,R0lGODlhDwAPANUAAAAAAP////7+/v39/fz8/Pv7+/j4+Pf39/X19fHx8e/v7+7u7u3t7evr6+rq6ufn5+bm5uXl5eLi4uDg4N/f39zc3Nra2tnZ2dTU1NPT09LS0tDQ0M/Pz87Ozs3NzbOzs39/f3V1dVdXVz4+PiMjI////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAPAA8AAAaawJKwpJhgPJiJYjg0SCqNg+DQqEgMzc2DMOh2CY8NtiSBFM5oNERCtBwMAIBhHjccLMUIAsEBkBAkABx7EUYNCYgfACMAH4gJDUcMC5QLcQCVCwxIEQ6eIQCgIZ4OEUkVEBAgACIQIgAgqRVKGhQUcba3ALYaSxIZF8HCwhlsJQYeGxjLzBgbHmPHEh4dHNYdHldMQkVHSUtDQQA7";
  580. img.addEventListener( 'click', leave, false );
  581. this.div.insertBefore( img, this.div.firstChild );
  582. }
  583.  
  584. //----------------------------------------------------------------
  585. // Apply to all links in the document
  586. //----------------------------------------------------------------
  587. // FIXME! Does not work on content loaded after page load!
  588. Array.prototype.forEach.call( document.querySelectorAll("a"), function(link)
  589. {
  590. var url = link.href;
  591. for ( var it in sites )
  592. {
  593. var site = sites[it];
  594. var re = site.match && site.match( url );
  595. if ( re )
  596. {
  597. (new linkPlayer( link )).source( link, re, site );
  598. }
  599. }
  600. } );
  601.  
  602. // Make it all look pretty
  603. addStyle('\
  604. div.TFProfile { \
  605. position:absolute !important; \
  606. z-index:9999999 !important; \
  607. background-color:#F8F8FF !important; \
  608. border: solid 1px #C0C0C0 !important; \
  609. min-width:200px !important; \
  610. padding:5px 10px; \
  611. -webkit-box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.3); \
  612. box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.3); } \
  613. \
  614. div.TFProfile img { \
  615. float:right !important;\
  616. margin:-5px 0px 0px 0px !important;\
  617. background-color: #cbcbcb;\
  618. display: block;\
  619. height: 18px;\
  620. width: 36px;\
  621. font-family: Verdana, Arial, Helvetica, sans-serif;\
  622. font-size: 11px;\
  623. font-weight: bold;color: #fff;\
  624. text-decoration: none;\
  625. text-align:center;\
  626. cursor: pointer;\
  627. line-height: 16px;\
  628. border: none;\
  629. -webkit-transition: background 100ms ease-in-out;\
  630. -moz-transition: background 100ms ease-in-out;\
  631. -ms-transition: background 100ms ease-in-out;\
  632. -o-transition: background 100ms ease-in-out;\
  633. transition: background 100ms ease-in-out; } \
  634. \
  635. div.TFProfile img:hover { \
  636. background-color: #de5044;\
  637. } \
  638. \
  639. div.TFProfile p { \
  640. letter-spacing:0px !important; \
  641. text-align:left !important; \
  642. color:#555!important; \
  643. padding:0!important; \
  644. margin:0px!important; \
  645. display: block !important; \
  646. border: none !important; \
  647. font-family: Verdana, Arial, Helvetica, sans-serif; \
  648. font-size: 10px; \
  649. font-style: normal; \
  650. line-height: normal; \
  651. font-weight: normal; \
  652. font-variant: normal; \
  653. color: #4c4c4c; \
  654. text-decoration: none; } \
  655. \
  656. div.TFProfile p.TFProfile_Done>a { \
  657. font-family:Verdana, Arial, Helvetica, sans-serif; \
  658. font-size:9px; \
  659. font-style:normal; \
  660. line-height:normal; \
  661. font-weight:700; \
  662. font-variant:normal; \
  663. text-decoration:none; \
  664. letter-spacing:0 !important; \
  665. text-align:left !important; \
  666. color:#f8f8f8; \
  667. border:1px solid #679bf3; \
  668. background-color:#77a7f9; \
  669. width:auto; \
  670. height:auto; \
  671. display:block!important; \
  672. margin:2px 0px!important; \
  673. padding:5px!important } \
  674. \
  675. div.TFProfile p.TFProfile_Done>a:hover { \
  676. color:#fff; \
  677. border:1px solid #4585f3; \
  678. -webkit-box-shadow:1px 1px 2px 0 rgba(0,0,0,0.1);\
  679. box-shadow:1px 1px 2px 0 rgba(0,0,0,0.1);\
  680. background: #77a7f9;\
  681. background: -moz-linear-gradient(top, #77a7f9 0%, #699cf2 100%);\
  682. background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#77a7f9), color-stop(100%,#699cf2));\
  683. background: -webkit-linear-gradient(top, #77a7f9 0%,#699cf2 100%);\
  684. background: -o-linear-gradient(top, #77a7f9 0%,#699cf2 100%);\
  685. background: -ms-linear-gradient(top, #77a7f9 0%,#699cf2 100%);\
  686. background: linear-gradient(to bottom, #77a7f9 0%,#699cf2 100%);\
  687. filter: progid:DXImageTransform.Microsoft.gradient( startColorstr="#77a7f9", endColorstr="#699cf2",GradientType=0 );} \
  688. \
  689. div.TFProfile p.TFProfile_Pending { \
  690. font-family:Verdana, Arial, Helvetica, sans-serif !important; \
  691. font-size:9px !important; \
  692. font-style:normal !important; \
  693. line-height:normal !important; \
  694. font-weight:700 !important; \
  695. font-variant:normal !important; \
  696. text-decoration:none !important; \
  697. letter-spacing:0 !important; \
  698. text-align:left !important; \
  699. color:#b1b1b1 !important; \
  700. border:1px solid #cbcbcb !important; \
  701. background-color:#e5e5e5 !important; \
  702. width:auto !important; \
  703. height:auto !important; \
  704. display:block !important; \
  705. margin:2px 0px !important;\
  706. padding:5px !important } \
  707. \
  708. div.TFProfile p.TFProfile_Missing { \
  709. display:none!important; \
  710. } \
  711. div.TFProfile article { \
  712. border-bottom: 1px dotted #C0C0C0; \
  713. padding: 5px 0px; \
  714. } \
  715. div.TFProfile article:last-child { \
  716. border-bottom: none; \
  717. } \
  718. ');
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement