--- /dev/null
+(function(){
+ 'use strict';
+
+ function tick() { return $('<span class="tick tracker-mark">✔</span>') }
+ function xmark() { return $('<span class="x tracker-mark">✘</span>') }
+
+ function update_tracker(){
+ var data = localStorage.getItem('tracker_data');
+ var user = localStorage.getItem('tracker_username');
+ if(!data)
+ return;
+ data = JSON.parse(data);
+ var solved = {};
+ var attempted = {};
+ var solvednr = 0;
+ var attemptednr = 0;
+ data.problems.forEach(function(e){
+ if(e.solved){
+ solved[e.problem] = 1;
+ solvednr++;
+ } else {
+ attempted[e.problem] = 1;
+ attemptednr++;
+ }
+ });
+
+ var contests = {};
+ data.contests.forEach(function(e){
+ contests[e.contest] = 1;
+ });
+
+ $('#tracker_userlink').html(data.name);
+ $('#tracker_solved').html(solvednr);
+ $('#tracker_attempted').html(attemptednr);
+ $('#tracker_contests').html(data.contests.length);
+
+ $('.tracker-mark').detach();
+ if(location.pathname == '/pb/')
+ $('table').find('.name').find('a').each(function() {
+ var id = $(this).attr('href').split('?', 2)[0];
+ if(solved[id])
+ $(this).parent().append(tick());
+ else if(attempted[id])
+ $(this).parent().append(xmark());
+ });
+
+ if(location.pathname == '/ct/')
+ $('table').find('.name').find('a').each(function() {
+ var id = $(this).attr('href').substr(4);
+ if(contests[id])
+ $(this).parent().append(tick());
+ });
+
+ if(location.pathname == '/log/')
+ $('table').find('tbody').find('tr').each(function() {
+ if($(this).find('.owner').find('a').attr('href') != "/us/" + user)
+ return;
+ $(this).find('.id').append($(this).find('.r0').size() ? tick() : xmark());
+ });
+ }
+
+ function start_tracking(user){
+ localStorage.setItem('tracker_username', user);
+ $('#tracker_userlink').attr('href', '/us/' + user).html(user);
+ $('#tracker_tracking').removeClass('hidden');
+ $('#tracker_form').addClass('hidden');
+ update_tracker();
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '/us/' + user);
+ xhr.setRequestHeader('Accept', 'application/json');
+ xhr.onload = function () {
+ localStorage.setItem('tracker_data', this.responseText);
+ update_tracker();
+ };
+ xhr.send();
+ }
+
+ function stop_tracking(){
+ $('.tracker-mark').detach();
+ localStorage.removeItem('tracker_username');
+ localStorage.removeItem('tracker_data');
+ $('#tracker_tracking').addClass('hidden');
+ $('#tracker_form').removeClass('hidden');
+ }
+
+ $( document ).ready(function(){
+ $('#tracker').detach().prependTo($('#sidebar')).removeClass('hidden');
+ $('#tracker_button').on('click', function() { start_tracking($('#tracker_username').val()) });
+ $('#tracker_stop').on('click', stop_tracking);
+
+ if(localStorage.getItem('tracker_username'))
+ start_tracking(localStorage.getItem('tracker_username'));
+ });
+})();
<div id="content">Content goes here</div>
+<div id="tracker">
+<h1>Track user</h1>
+<div id="tracker_form">
+<div class="form-group">
+<label for="tracker_username">Username</label>
+<input type="text" id="tracker_username" class="form-control">
+</div>
+<button id="tracker_button" class="btn">Start tracking</button>
+</div>
+
+<div id="tracker_tracking" class="hidden">
+Tracking <a href="#" id="tracker_userlink"></a>.<br>
+<a href="#" id="tracker_stop">Stop tracking</a>
+<dl class="dl-horizontal">
+<dt>Solved</dt> <dd id="tracker_solved">?</dd>
+<dt>Attempted</dt> <dd id="tracker_attempted">?</dd>
+<dt>Contests</dt> <dd id="tracker_contests">?</dd>
+</dl>
+</div>
+</div>
+
<footer>
Dilmom: Why don't you call your product the Gruntmaster 6000?<br>
Dilbert: What kind of product do you see when you imagine a Gruntmaster 6000?<br>