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