Advertisement
Guest User

Multi rating graph for Codeforces

a guest
Jun 14th, 2021
595
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name           Multi rating graph for Codeforces
  3. // @namespace      http://yak2.myhome.cx/
  4. // @description    Enable to show rating history graph with other accounts on profile pages at Codeforces
  5. // @license        http://creativecommons.org/publicdomain/zero/1.0/
  6. // @copyright      yak_ex
  7. // @version        1.3
  8. // @include        https://www.codeforces.com/profile/*
  9. // @include        https://codeforces.com/profile/*
  10. // @include        https://www.codeforces.ru/profile/*
  11. // @include        https://codeforces.ru/profile/*
  12. // ==/UserScript==
  13.  
  14. // v1.3  2015/05/05 Sync with site changes.
  15. // v1.2  2014/06/05 Autocomplete account names
  16. //                  Keep the color of the highest dots
  17. // v1.1  2013/03/15 Fix failure to get log-in account
  18. //                  Version jump because Chrome recognizes 0.0x as 1.0
  19. // v0.03 2011/04/17 Show log-in account always
  20. // v0.02 2011/04/16 Adjust yaxis scale
  21. //                  Warn if data can't be obtained
  22. // v0.01 2011/04/16 Initial version
  23.  
  24. ///////////////////////////////////////////////////////////////////////
  25. //
  26. // The following part is executed in content page scope
  27. //
  28.  
  29. function extract_data(cont)
  30. {
  31.     var re1 = new RegExp('data\\.push\\(([\\S\\s]*?)\\);\\s*data\\.push\\(([\\S\\s]*?)\\);', 'm');
  32.     return re1.test(cont) ? [RegExp.$1, RegExp.$2] : undefined;
  33. }
  34.  
  35. function extract_scale(cont)
  36. {
  37.     var re2 = new RegExp('yaxis:\\s*{\\s*min:\\s*(\\d+),\\s*max:\\s*(\\d+),');
  38.     return re2.test(cont) ? [RegExp.$1, RegExp.$2] : undefined;
  39. }
  40.  
  41. function get_account_data(id)
  42. {
  43.     var xhr = new XMLHttpRequest();
  44.     xhr.open('GET', 'https://' + window.location.host + '/profile/' + id, false);
  45.     xhr.send(null);
  46.     if(xhr.status == 200) {
  47.         return [extract_data(xhr.responseText), extract_scale(xhr.responseText)];
  48.     }
  49.     return undefined;
  50. }
  51.  
  52. function update_graph(input)
  53. {
  54.     if(input == null) return;
  55.     var handle = window.location.href.match(/[^/]*$/);
  56.     input = handle + ' ' + input;
  57.     var accounts = input.split(' ');
  58.     var check = {};
  59.     data = new Array();
  60.     datas = [];
  61.     var mymin = 900, mymax = 2000;
  62.     var idx = 0;
  63.     for(var i = 0; i < accounts.length; ++i) {
  64.         if(accounts[i] != '' && check[accounts[i]] == undefined) {
  65.             check[accounts[i]] = 1;
  66.             var d = get_account_data(accounts[i]);
  67.             if(d != undefined && d[0] != undefined) {
  68.                 data.push(eval(d[0][0]));
  69.                 data.push(eval(d[0][1]));
  70.                 datas[2*idx] = { label: accounts[i], data: data[2*idx] };
  71.                 datas[2*idx+1] = { clickable: false, hoverable: false, color: "red", data: data[2*idx+1], points: {radius: 1} };
  72.                 ++idx;
  73.                 if(d[1] != undefined) {
  74.                     if(d[1][0] < mymin) mymin = d[1][0];
  75.                     if(d[1][1] > mymax) mymax = d[1][1];
  76.                 }
  77.             } else {
  78.                 alert("Can't get information for account: " + accounts[i] + ".");
  79.             }
  80.         }
  81.     }
  82.     if(idx == 1) {
  83.         options.legend.position = "ne";
  84.     } else {
  85.         options.legend.position = "se";
  86.     }
  87.     options.yaxis.min = mymin;
  88.     options.yaxis.max = mymax;
  89.     options.yaxis.panRange = [mymin, mymax];
  90.     plot = $.plot($("#usersRatingGraphPlaceholder"), datas, options);
  91.     $("#usersRatingGraphPlaceholder .legend").unbind("click");
  92.     $("#usersRatingGraphPlaceholder .legend").bind("click", account_manage);
  93. }
  94.  
  95. function account_manage()
  96. {
  97.     var handle = window.location.href.match(/[^/]*$/);
  98.     var dialog = $('<div id="account-dialog"/>').css({
  99.         position:'fixed',padding:'5px',width:'30em',zIndex:2000,left:'50%',top:'50%',marginTop:'-3.5em',marginLeft:'-15em',
  100.         border:'1px solid', borderRadius:'5px',background:'rgb(255,255,255)',boxShadow:'rgb(64,64,64) 5px 5px 5px'
  101.     }).html(
  102.         '<p>Input space-separated accounts without this account.</p>' +
  103.         '<form id="account-form"><p><input type="text" id="accounts" size="40" value="'+(handle !=  login_account ? login_account : '')+'"></p>' +
  104.         '<p><input type="submit" id="ok" value="OK"> <input type="button" id="cancel" value="cancel"></p></form>'
  105.     );
  106.     $('p', dialog).css({margin:'1em'});
  107.     $('#cancel', dialog).click(function() {
  108.         $('#account-dialog').remove();
  109.         $('#account-dialog-blocker').remove();
  110.     });
  111.     $('#account-form', dialog).submit(function() {
  112.         var input = $('#accounts').val();
  113.         $('#account-dialog').remove();
  114.         $('#account-dialog-blocker').remove();
  115.         update_graph(input);
  116.         return false;
  117.     }).keydown(function(e) {
  118.         if(e.keyCode == 27) {
  119.             $('#cancel').click();
  120.         }
  121.     });
  122.     var blocker = $('<div id="account-dialog-blocker"/>').css({
  123.         position:'fixed',top:0,left:0,bottom:0,right:0,width:'100%',height:'100%',zIndex:15,
  124.         background:'rgb(64,64,64)',opacity:0.75
  125.     });
  126.     $('body').append(blocker);
  127.     $('body').append(dialog);
  128.     $('#accounts').autocomplete("/data/handles", {
  129.         delay: 200,
  130.         width: 200,
  131.         selectFirst: false,
  132.         matchContains: true,
  133.         multiple: true,
  134.         multipleSeparator: ' ',
  135.         minChars: 3,
  136.         scroll: true,
  137.     });
  138.     $('#accounts').focus();
  139. }
  140.  
  141. ///////////////////////////////////////////////////////////////////////
  142. //
  143. // The following part is executed in userjs scope.
  144. //
  145.  
  146. function add_unbind(cont)
  147. {
  148.     var marker = '$("#placeholder").bind("plothover"';
  149.     return cont.replace(marker, '$("#placeholder").unbind("plothover");\n' + marker);
  150. }
  151.  
  152. function get_login_account()
  153. {
  154.     var e = document.getElementById('header');
  155.     var re3 = new RegExp('<a href="/profile/([^"]*)">[^<]*</a>[^<]*<a href="[^"]*/logout">');
  156.     return re3.test(e.innerHTML) ? RegExp.$1 : undefined;
  157. }
  158.  
  159. function disable_default_plot(cont)
  160. {
  161.     return cont.replace('var plot = $.plot($("#placeholder"), datas, options);', '').replace('var ctx = plot.getCanvas().getContext("2d");', '');
  162. }
  163.  
  164. function add_account_manage(cont)
  165. {
  166.     var marker = 'var prev = -1;';
  167.     var target = '';
  168.     target += 'var extract_data = ' + extract_data + ';\n';
  169.     target += 'var extract_scale = ' + extract_scale + ';\n';
  170.     target += 'var get_account_data = ' + get_account_data + ';\n';
  171.     var login_account = get_login_account();
  172.     if(login_account != undefined) {
  173.         target += 'var login_account = "' + get_login_account() + '";\n';
  174.     } else {
  175.         target += 'var login_account = "";\n';
  176.     }
  177.     target += 'options.legend = {};\n';
  178.     target += 'var account_manage;\n';
  179.     target += 'var update_graph = ' + update_graph + ';\n';
  180.     target += 'account_manage = ' + account_manage + ';\n';
  181.     target += 'update_graph(login_account);\n';
  182.     target += '$("#placeholder .legend").unbind("click");\n';
  183.     target += '$("#placeholder .legend").bind("click", account_manage);\n';
  184. // CAUTION FRAGILE: monkey patch for Autocompleter to handle multiple words correctly
  185.     target += '$(function() {\n';
  186.     target += 'var old = $.Autocompleter;\n';
  187.     target += 'eval("$.Autocompleter = " + (""+$.Autocompleter).replace("currentValue == q", "lastWord(currentValue) == q"));\n';
  188.     target += '$.Autocompleter.defaults = old.defaults;$.Autocompleter.Cache = old.Cache;$.Autocompleter.Select = old.Select;\n';
  189.     target += '});\n';
  190.  
  191.     return cont.replace(marker, target + marker);
  192. }
  193.  
  194. function get_target_script()
  195. {
  196.     var e = document.getElementById('pageContent').getElementsByTagName('script');
  197.     for(var i = 0; i < e.length; ++i) {
  198.         if(e[i].textContent.match(/data\.push/) != null) {
  199.             return e[i];
  200.         }
  201.     }
  202. }
  203.  
  204. script = document.createElement('script');
  205. script.setAttribute("type", "application/javascript");
  206. script.textContent = disable_default_plot(add_account_manage(add_unbind(get_target_script().textContent)));
  207.  
  208. document.body.appendChild(script);
  209. document.body.removeChild(script);
  210.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement