]> de.git.xonotic.org Git - xonotic/xonstat.git/commitdiff
Merge zykure-approved, my fixes, and merge fixes :D
authorAnt Zucaro <azucaro@gmail.com>
Fri, 19 Apr 2013 00:59:52 +0000 (20:59 -0400)
committerAnt Zucaro <azucaro@gmail.com>
Fri, 19 Apr 2013 00:59:52 +0000 (20:59 -0400)
1  2 
xonstat/models.py
xonstat/static/css/app.css
xonstat/static/css/app.min.css
xonstat/templates/main_index.mako
xonstat/templates/player_index.mako
xonstat/templates/player_info.mako

diff --combined xonstat/models.py
index 6ee379cf706ae8c600f14c92893f417bafda80d3,91901d6e0b5ce3b2c44adf1e479693b4afdb72f5..bda038bc82e9ba8b403e43364b5f6561774ca167
@@@ -10,7 -10,7 +10,7 @@@ from sqlalchemy.orm import mappe
  from sqlalchemy.orm import scoped_session
  from sqlalchemy.orm import sessionmaker
  from sqlalchemy.ext.declarative import declarative_base
- from xonstat.util import strip_colors, html_colors, pretty_date
+ from xonstat.util import qfont_decode, strip_colors, html_colors, pretty_date
  
  log = logging.getLogger(__name__)
  
@@@ -19,11 -19,11 +19,11 @@@ Base = declarative_base(
  
  # define objects for all tables
  class Player(object):
 -    def nick_html_colors(self):
 +    def nick_html_colors(self, limit=None):
          if self.nick is None:
              return "Anonymous Player"
          else:
 -            return html_colors(self.nick)
 +            return html_colors(self.nick, limit)
  
      def nick_strip_colors(self):
          if self.nick is None:
@@@ -41,7 -41,7 +41,7 @@@
          return {'player_id':self.player_id, 'nick':self.nick,
              'joined':self.create_dt.strftime('%Y-%m-%dT%H:%M:%SZ'),
              'active_ind':self.active_ind, 'location':self.location,
-             'stripped_nick':self.stripped_nick}
+             'stripped_nick':qfont_decode(self.stripped_nick)}
  
      def epoch(self):
          return timegm(self.create_dt.timetuple())
@@@ -102,7 -102,7 +102,7 @@@ class Map(object)
  
  
  class Game(object):
 -    def __init__(self, game_id=None, start_dt=None, game_type_cd=None, 
 +    def __init__(self, game_id=None, start_dt=None, game_type_cd=None,
              server_id=None, map_id=None, winner=None):
          self.game_id = game_id
          self.start_dt = start_dt
@@@ -144,11 -144,11 +144,11 @@@ class PlayerGameStat(object)
          else:
              return strip_colors(self.nick)
  
 -    def nick_html_colors(self):
 +    def nick_html_colors(self, limit=None):
          if self.nick is None:
              return "Anonymous Player"
          else:
 -            return html_colors(self.nick)
 +            return html_colors(self.nick, limit)
  
      def team_html_color(self):
          if self.team == 5:
@@@ -206,10 -206,10 +206,10 @@@ class Hashkey(object)
  
  class PlayerNick(object):
      def __repr__(self):
-         return "<PlayerNick(%s, %s)>" % (self.player_id, self.stripped_nick)
+         return "<PlayerNick(%s, %s)>" % (self.player_id, qfont_decode(self.stripped_nick))
  
      def to_dict(self):
-         return {'player_id':self.player_id, 'name':self.stripped_nick}
+         return {'player_id':self.player_id, 'name':qfont_decode(self.stripped_nick)}
  
  
  class PlayerElo(object):
  
  class PlayerRank(object):
  
 -    def nick_html_colors(self):
 +    def nick_html_colors(self, limit=None):
          if self.nick is None:
              return "Anonymous Player"
          else:
 -            return html_colors(self.nick)
 +            return html_colors(self.nick, limit)
  
      def __repr__(self):
          return "<PlayerRank(pid=%s, gametype=%s, rank=%s)>" % (self.player_id, self.game_type_cd, self.rank)
index f825fe61cc7f850980ad66e830cb89c7495b48b8,48c91a388591b142ac54cf321e1820bd5d4bea41..7cabed5799af38c197ac9e08ac1e2a4a977056d8
@@@ -239,10 -239,12 +239,18 @@@ table td 
    float: left;
  }
  
++/* elo colors */
 +.eloup { color: green; }
 +.elodown { color: rgb(190,0,0); }
 +.eloneutral { color: gray; }
 +
++/* limit player nick lengths */
+ .player-nick {
+   overflow: hidden;
+   text-overflow: ellipsis;
+   white-space: nowrap;
+ }
  /* Navigation links */
  .pagination > li > a, .pagination > li > span {
      background-color: #111111;
index acbff2ca45727515151fa04e5d948395fa7fbeee,889ff7ebbf934b8402c4f1e1845af514175c0e9a..c8ada11684f66627be0fd31ac07559b5873cbeb6
@@@ -1,1 -1,1 +1,1 @@@
- @font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.eloup{color:green}.elodown{color:#be0000}.eloneutral{color:gray}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
 -@font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.player-nick{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
++@font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.eloup{color:green}.elodown{color:#be0000}.eloneutral{color:gray}.player-nick{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
index 3622c793cd9a52266a265ff4979e08d5b7fe580e,7e7b0d86a5777462e78d56c2fcb493a529ab4ff4..4e84cbb06719ab3f02613a424974906fbda1af7a
@@@ -56,8 -56,8 +56,8 @@@ Leaderboar
          % for r in rs:
          <tr>
            <td>${i}</td>
-           <td><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors(18)|n}</a></td>
 -          <td class="player-nick" style="max-width: 16em;"><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors()|n}</a></td>
 -          <td>${round(r.elo, 3)}</td>
++          <td><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors()|n}</a></td>
 +          <td>${int(round(r.elo))}</td>
          </tr>
          <% i = i+1 %>
          % endfor
@@@ -90,7 -90,7 +90,7 @@@
          <tr>
            <td>${i}</td>
            % if player_id != '-':
-           <td><a href="${request.route_url('player_info', id=player_id)}" title="Go to the player info page for this player">${nick|n}</a></td>
+           <td class="player-nick"><a href="${request.route_url('player_info', id=player_id)}" title="Go to the player info page for this player">${nick|n}</a></td>
            % else:
            <td>${nick|n}</td>
            % endif
            <td><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
            <td><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the map detail page for this map">${rg.map_name}</a></td>
            <td><span class="abstime" data-epoch="${rg.epoch}" title="${rg.start_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${rg.fuzzy_date}</span></td>
-           <td>
+           <td class="player-nick">
              % if rg.player_id > 2:
              <a href="${request.route_url('player_info', id=rg.player_id)}" title="Go to the player info page for this player">${rg.nick_html_colors|n}</a></td>
              % else:
index 9eb319780caeeb27e8330b3953f15152bdbeebbb,418d57ef1050ef73fca6293a92b2a084dae6d4c4..d23decab93d3891a405a83e78ebaf2af619c41f9
@@@ -26,18 -26,12 +26,18 @@@ Player Inde
          <th style="width:100px;">Player ID</th>
          <th>Nick</th>
          <th class="create-dt">Joined</th>
 +        <th></th>
        </tr>
      % for player in players:
        <tr>
          <td>${player.player_id}</th>
-         <td><a href="${request.route_url("player_info", id=player.player_id)}" title="Go to this player's info page">${player.nick_html_colors()|n}</a></th>
+         <td class="player-nick"><a href="${request.route_url("player_info", id=player.player_id)}" title="Go to this player's info page">${player.nick_html_colors()|n}</a></th>
          <td><span class="abstime" data-epoch="${player.epoch()}" title="${player.create_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${player.joined_pretty_date()}</span></th>
 +        <td class="tdcenter">
 +          <a href="${request.route_url("player_game_index", player_id=player.player_id, page=1)}" title="View recent games by this player">
 +            <i class="glyphicon glyphicon-list"></i>
 +          </a>
 +        </td>
        </tr>
      % endfor
      </table>
index 37086ccc25d2583e261e6641676222041da0db1b,f51dac9627cf265cc62e2bfff5c061b2b55916bf..70fd74e12ee4ad316fdd3ca3d2cc30e16a5d7280
@@@ -220,6 -220,15 +220,15 @@@ Player Informatio
            % if g.game_type_cd in fav_maps:
            Favorite Map: <small>${fav_maps[g.game_type_cd].map_name} <br /></small>
            % endif
+           
+           % if g.game_type_cd == 'ctf':
+           % if overall_stats[g.game_type_cd].total_captures is not None:
+           <small><a href="${request.route_url("player_captimes", id=player.player_id)}">Fastest flag captures...</a></small>
+           % endif
+           % else:
+           <small><br /></small>
+           % endif
+           
            </p>
          </div>
          <div class="span5">
            % if  overall_stats[g.game_type_cd].cap_ratio is not None:
            Cap Ratio: <small>${round(overall_stats[g.game_type_cd].cap_ratio,2)} (${overall_stats[g.game_type_cd].total_captures} captures, ${overall_stats[g.game_type_cd].total_pickups} pickups) <br /></small>
            % endif
+           % else:
+           <small><br /></small>
            % endif
            </p>
          </div>
      <ul id="gbtab" class="nav nav-tabs">
        % for g in games_played:
        <li>
-       <a href="#tab-${g.game_type_cd}" data-toggle="tab">
+       <a href="#tab-${g.game_type_cd}" data-toggle="tab" alt="${g.game_type_cd}" title="">
          <span class="sprite sprite-${g.game_type_cd}"> </span><br />
          ${g.game_type_cd} <br />
          <small>(${g.games})</small>
  <div class="row">
    <div class="span12">
      <h3>Accuracy</h3>
-     <div id="acc-graph" class="flot" style="width:100%; height:200px;">
+     <div id="acc-graph" class="flot" style="width:95%; height:200px;">
      </div>
  
      <div class="weapon-nav accuracy-nav">
  <div class="row">
    <div class="span12">
      <h3>Damage Efficiency</h3>
-     <div id="dmg-graph" class="flot" style="width:100%; height:200px;">
+     <div id="dmg-graph" class="flot" style="width:95%; height:200px;">
      </div>
  
      <div class="weapon-nav damage-nav">
        <tr>
          <td class="tdcenter"><a class="btn btn-primary btn-small" href="${request.route_url('game_info', id=rg.game_id)}" title="View detailed information about this game">view</a></td>
          <td class="tdcenter"><span class="sprite sprite-${rg.game_type_cd}" alt="${rg.game_type_cd}" title="${rg.game_type_descr}"></span></td>
-         <td>${rg.server_name}</td>
-         <td>${rg.map_name}</td>
+         <td><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
+         <td><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the detail page for this map">${rg.map_name}</a></td>
          <td>
            % if rg.team != None:
            % if rg.team == rg.winner:
            <a href="${request.route_url('game_info', id=rg.game_id, _query={'show_elo':1})}" title="View detailed information about this game">
              % if rg.elo_delta is not None:
              % if round(rg.elo_delta,2) > 0:
 -            <span title="Elo went up by ${round(rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-up"></i></span>
 +            <span class="eloup" title="Elo went up by ${round(rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-up"></i></span>
              % elif round(rg.elo_delta,2) < 0:
 -            <span title="Elo went down by ${round(-rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-down"></i></span>
 +            <span class="elodown" title="Elo went down by ${round(-rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-down"></i></span>
              % else:
 -            <span title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
 +            <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
              % endif
              % else:
 -            <span title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
 +            <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
              % endif
            </a>
          </td>