Skip to content

Commit ac4d03b

Browse files
committed
release version 0.0.1
0 parents  commit ac4d03b

20 files changed

+338
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# openjudge-helper
2+
3+
[WIP] 一个让你更方便统计 noi.openjudge.cn 上的学生信息的浏览器(Chrome)插件
4+
5+
## 安装方法
6+
7+
将本插件文件(openjudge-helper.crx)拖入 Chrome 浏览器窗口即可。
8+
9+
## 使用方法
10+
11+
在「题目」页面勾选需要纳入统计的题目。
12+
13+
![problem.png](https://i.loli.net/2020/08/22/uKOmqMH5lpt9vVy.png)
14+
15+
在「状态」页面勾选需要纳入统计的用户。
16+
17+
![status.png](https://i.loli.net/2020/08/22/pDKOZ9MFW1uLqx3.png)
18+
19+
点击本插件图标,在「报表」页面可访问统计信息。
20+
21+
![report.png](https://i.loli.net/2020/08/22/lHPcegn57ZGRpmj.png)
22+
23+
## To-do
24+
25+
[] 优化报表结构
26+
27+
[] 支持导出学生「学习报告」
28+
29+
[] 加入「班级」概念
30+
31+
[] 支持导出配置文件

background.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
chrome.runtime.onInstalled.addListener(function() {
2+
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
3+
chrome.declarativeContent.onPageChanged.addRules([{
4+
conditions: [
5+
new chrome.declarativeContent.PageStateMatcher({
6+
pageUrl: {hostEquals: 'noi.openjudge.cn'}
7+
})
8+
],
9+
actions: [new chrome.declarativeContent.ShowPageAction()]
10+
}]);
11+
});
12+
13+
chrome.storage.sync.set({students: []});
14+
chrome.storage.sync.set({problems: []});
15+
});
16+
17+
chrome.runtime.onMessage.addListener(
18+
function(request, sender, sendResponse) {
19+
switch (request.operation) {
20+
case 'add_student':
21+
console.log('add student');
22+
chrome.storage.sync.get('students', data => {
23+
let new_student = {userId: request.userId, userName: request.userName}
24+
data.students.push(new_student);
25+
chrome.storage.sync.set({students: data.students});
26+
});
27+
break;
28+
case 'del_student':
29+
console.log('del student');
30+
chrome.storage.sync.get('students', data => {
31+
data.students = data.students.filter(s => s.userId != request.userId || s.userName != request.userName);
32+
chrome.storage.sync.set({students: data.students});
33+
});
34+
break;
35+
case 'add_problem':
36+
console.log('add ' + request.problems.length + ' problem');
37+
chrome.storage.sync.get('problems', data => {
38+
data.problems = data.problems.concat(request.problems);
39+
chrome.storage.sync.set({problems: data.problems});
40+
});
41+
break;
42+
case 'del_problem':
43+
console.log('del ' + request.problems.length + ' problem');
44+
chrome.storage.sync.get('problems', data => {
45+
request.problems.forEach(p => {
46+
data.problems = data.problems.filter(pp => pp.chapterId != p.chapterId || pp.problemId != p.problemId);
47+
});
48+
chrome.storage.sync.set({problems: data.problems});
49+
});
50+
break;
51+
}
52+
}
53+
);

images/.DS_Store

6 KB
Binary file not shown.

images/favicon_io.zip

63.4 KB
Binary file not shown.

images/ojh128.png

9.67 KB
Loading

images/ojh16.png

494 Bytes
Loading

images/ojh32.png

989 Bytes
Loading

images/ojh48.png

3.61 KB
Loading

jquery-3.5.1.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

manifest.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "Openjudge Helper",
3+
"version": "0.0.1",
4+
"description": "Better experience on noi.openjudge.cn",
5+
"permissions": [
6+
"declarativeContent",
7+
"storage",
8+
"activeTab",
9+
"http://openjudge.cn/"
10+
],
11+
"background": {
12+
"scripts": ["jquery-3.5.1.min.js", "background.js"],
13+
"persistent": false
14+
},
15+
"page_action": {
16+
"default_popup": "popup.html",
17+
"default_icon": {
18+
"16": "images/ojh16.png",
19+
"32": "images/ojh32.png",
20+
"48": "images/ojh48.png",
21+
"128": "images/ojh128.png"
22+
}
23+
},
24+
"icons": {
25+
"16": "images/ojh16.png",
26+
"32": "images/ojh32.png",
27+
"48": "images/ojh48.png",
28+
"128": "images/ojh128.png"
29+
},
30+
"options_page": "options.html",
31+
"content_scripts": [
32+
{
33+
"matches": ["*://noi.openjudge.cn/*/status/*"],
34+
"js": ["jquery-3.5.1.min.js", "status.js"]
35+
},
36+
{
37+
"matches": ["*://noi.openjudge.cn/*/"],
38+
"exclude_matches": [
39+
"*://noi.openjudge.cn/*/status/*",
40+
"*://noi.openjudge.cn/*/clarify/*",
41+
"*://noi.openjudge.cn/*/ranking/*"
42+
],
43+
"js": ["jquery-3.5.1.min.js", "problem.js"]
44+
}
45+
],
46+
"manifest_version": 2
47+
}

options.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
</head>
6+
<body>
7+
<h1>这个页面会有的</h1>
8+
<script src="jquery-3.5.1.min.js"></script>
9+
<script src="options.js"></script>
10+
</body>
11+
</html>

options.js

Whitespace-only changes.

popup.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
</head>
6+
<body>
7+
<button id="options">选项</button>
8+
<button id="report">报表</button>
9+
<script src="jquery-3.5.1.min.js"></script>
10+
<script src="popup.js"></script>
11+
</body>
12+
</html>

popup.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*document.addEventListener('DOMContentLoaded', function() {
2+
document.getElementById("options").addEventListener("click", function() {
3+
chrome.tabs.create({});
4+
});
5+
});*/
6+
7+
$('#options').click(() => {
8+
chrome.tabs.create({url: 'options.html'});
9+
});
10+
11+
$('#report').click(() => {
12+
chrome.tabs.create({url: 'report.html'});
13+
});

problem.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
$('thead tr').prepend($('<td>纳入统计<input id="problemall" type="checkbox" /></td>'));
2+
let checkboxTd = $('<td><input class="problemcheck" type="checkbox" /></td>');
3+
$('tbody tr').prepend(checkboxTd);
4+
5+
let currentCId = $('tbody .problem-id:first').children().prop('href').match(/[0-9]+/);
6+
7+
chrome.storage.sync.get('problems', function(data) {
8+
data.problems.forEach(function(problem) {
9+
if (problem.chapterId == currentCId) {
10+
$('.problem-id:contains(' + problem.problemId + ')').siblings(':first').children().prop('checked', true);
11+
}
12+
});
13+
if ($('.problemcheck:checked').length == $('.problemcheck').length)
14+
$('#problemall').prop('checked', true);
15+
});
16+
17+
$('#problemall').change(function () {
18+
if ($(this).prop('checked')) {
19+
20+
let problems = []
21+
$('.problemcheck').each(function() {
22+
23+
let chapterId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/g)[0];
24+
let problemId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/g)[1];
25+
let problemName = $(this).parent().siblings('.title').text();
26+
let problem = {chapterId: chapterId, problemId: problemId, problemName: problemName};
27+
28+
if (!$(this).prop('checked')) {
29+
30+
problems.push(problem);
31+
$(this).prop('checked', true);
32+
}
33+
});
34+
chrome.runtime.sendMessage({operation: 'add_problem', problems: problems}, undefined);
35+
36+
}
37+
else {
38+
39+
let problems = []
40+
$('.problemcheck').each(function() {
41+
42+
let chapterId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/)[0];
43+
let problemId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/g)[1];
44+
let problemName = $(this).parent().siblings('.title').text();
45+
let problem = {chapterId: chapterId, problemId: problemId, problemName: problemName};
46+
47+
if ($(this).prop('checked')) {
48+
49+
problems.push(problem);
50+
$(this).prop('checked', false);
51+
}
52+
});
53+
chrome.runtime.sendMessage({operation: 'del_problem', problems: problems}, undefined);
54+
}
55+
});
56+
57+
$('.problemcheck').change(function() {
58+
59+
let chapterId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/g)[0];
60+
let problemId = $(this).parent().siblings('.problem-id').children().prop('href').match(/[0-9]+/g)[1];
61+
let problemName = $(this).parent().siblings('.title').text();
62+
let problem = {chapterId: chapterId, problemId: problemId, problemName: problemName};
63+
64+
if ($(this).prop('checked')) {
65+
66+
chrome.runtime.sendMessage({operation: 'add_problem', problems: [problem]}, undefined);
67+
68+
if ($('.problemcheck:checked').length == $('.problemcheck').length)
69+
$('#problemall').prop('checked', true);
70+
}
71+
72+
else {
73+
74+
chrome.runtime.sendMessage({operation: 'del_problem', problems: [problem]}, undefined);
75+
76+
if ($('.problemcheck:checked').length != $('.problemcheck').length)
77+
$('#problemall').prop('checked', false);
78+
}
79+
});

report.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
</head>
6+
<body>
7+
<h1>题目完成情况</h1>
8+
<table id="user-problem">
9+
<thead>
10+
<tr>
11+
<th><strong>用户名</strong></th>
12+
</tr>
13+
</thead>
14+
<tbody>
15+
</tbody>
16+
</table>
17+
<script src="jquery-3.5.1.min.js"></script>
18+
<script src="report.js"></script>
19+
</body>
20+
</html>

report.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
let table = $('#user-problem');
2+
3+
chrome.storage.sync.get(['students', 'problems'], data => {
4+
data.problems.forEach((problem) => {
5+
$('#user-problem thead tr').append($('<th></th>').text(problem.problemName));
6+
});
7+
data.students.forEach((student) => {
8+
let tr = $('<tr></tr>');
9+
tr.append($('<td></td>').text(student.userName));
10+
let problemAccepted = [];
11+
$.get('http://openjudge.cn/user/' + student.userId + '/in/group-93/', function(data) {
12+
$(data).find('h4:contains(已解决)').next().find('a').each(function() {
13+
problem = $(this).prop('href').match(/[0-9]+/g);
14+
problemAccepted.push({chapterId: problem[0], problemId: problem[1]});
15+
});
16+
}).done(() => {
17+
data.problems.forEach((problem) => {
18+
let td = $('<td></td>');
19+
if (problemAccepted.filter(p => p.chapterId == problem.chapterId && p.problemId == problem.problemId).length)
20+
td.text('已完成');
21+
else
22+
td.text('未完成');
23+
tr.append(td);
24+
});
25+
$('#user-problem tbody').append(tr);
26+
});
27+
});
28+
});

status.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
$('thead tr').prepend($('<td>纳入统计</td>'));
2+
let checkboxTd = $('<td><input class="usercheck" type="checkbox" /></td>');
3+
$('tbody tr').prepend(checkboxTd);
4+
5+
chrome.storage.sync.get('students', function(data) {
6+
data.students.forEach(function(student) {
7+
//alert('.submit-user:contains(' + student.userName + ')');
8+
let td = $('.submit-user:contains(' + student.userName + ')');
9+
td.each(function() {
10+
//alert('yes');
11+
$(this).siblings(':first').children().prop('checked', true);
12+
});
13+
});
14+
});
15+
16+
$('.usercheck').change(function() {
17+
let userId = $(this).parent().siblings('.submit-user').children().prop('href').match(/[0-9]+/)[0];
18+
let userName = $(this).parent().siblings('.submit-user').children().text();
19+
if ($(this).prop('checked')) {
20+
chrome.runtime.sendMessage({operation: 'add_student', userId: userId, userName: userName}, undefined);
21+
$('.usercheck').each(function() {
22+
if ($(this).parent().siblings('.submit-user').children().text() == userName) {
23+
$(this).prop('checked', true);
24+
}
25+
});
26+
}
27+
else {
28+
chrome.runtime.sendMessage({operation: 'del_student', userId: userId, userName: userName}, undefined);
29+
$('.usercheck').each(function() {
30+
if ($(this).parent().siblings('.submit-user').children().text() == userName) {
31+
$(this).prop('checked', false);
32+
}
33+
});
34+
}
35+
});

student.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Student {
2+
userId;
3+
4+
constructor(userId) {
5+
this.userId = userId;
6+
}
7+
}

0 commit comments

Comments
 (0)