mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-12-23 19:51:52 +00:00
1165 lines
34 KiB
JavaScript
1165 lines
34 KiB
JavaScript
// locale
|
||
uojLocaleData = {
|
||
"username": {
|
||
"en": "Username",
|
||
"zh-cn": "用户名"
|
||
},
|
||
"contests::total score": {
|
||
"en": "Score",
|
||
"zh-cn": "总分"
|
||
},
|
||
"contests::n participants": {
|
||
"en": function(n) {
|
||
return n + " participant" + (n <= 1 ? '' : 's');
|
||
},
|
||
"zh-cn": function(n) {
|
||
return "共 " + n + " 名参赛者";
|
||
}
|
||
},
|
||
"click-zan::good": {
|
||
"en": "Good",
|
||
"zh-cn": "好评"
|
||
},
|
||
"click-zan::bad": {
|
||
"en": "Bad",
|
||
"zh-cn": "差评"
|
||
},
|
||
"editor::use advanced editor": {
|
||
"en": "use advanced editor",
|
||
"zh-cn": "使用高级编辑器"
|
||
},
|
||
"editor::language": {
|
||
"en": "Language",
|
||
"zh-cn": "语言"
|
||
},
|
||
"editor::browse": {
|
||
"en": "Browse",
|
||
"zh-cn": "浏览"
|
||
},
|
||
"editor::upload by editor": {
|
||
"en": "Upload by editor",
|
||
"zh-cn": "使用编辑器上传"
|
||
},
|
||
"editor::upload from local": {
|
||
"en": "Upload from local",
|
||
"zh-cn": "从本地文件上传"
|
||
}
|
||
};
|
||
|
||
function uojLocale(name) {
|
||
locale = $.cookie('uoj_locale');
|
||
if (uojLocaleData[name] === undefined) {
|
||
return '';
|
||
}
|
||
if (uojLocaleData[name][locale] === undefined) {
|
||
locale = 'zh-cn';
|
||
}
|
||
val = uojLocaleData[name][locale];
|
||
if (!$.isFunction(val)) {
|
||
return val;
|
||
} else {
|
||
var args = [];
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
args.push(arguments[i]);
|
||
}
|
||
return val.apply(this, args);
|
||
}
|
||
}
|
||
|
||
// utility
|
||
function strToDate(str) {
|
||
var a = str.split(/[^0-9]/);
|
||
return new Date(
|
||
parseInt(a[0]),
|
||
parseInt(a[1]) - 1,
|
||
parseInt(a[2]),
|
||
parseInt(a[3]),
|
||
parseInt(a[4]),
|
||
parseInt(a[5]),
|
||
0);
|
||
}
|
||
function dateToStr(date) {
|
||
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
|
||
}
|
||
function toFilledStr(o, f, l) {
|
||
var s = o.toString();
|
||
while (s.length < l) {
|
||
s = f.toString() + s;
|
||
}
|
||
return s;
|
||
}
|
||
function getPenaltyTimeStr(x) {
|
||
var ss = toFilledStr(x % 60, '0', 2);
|
||
x = Math.floor(x / 60);
|
||
var mm = toFilledStr(x % 60, '0', 2);
|
||
x = Math.floor(x / 60);
|
||
var hh = x.toString();
|
||
return hh + ':' + mm + ':' + ss;
|
||
}
|
||
|
||
function htmlspecialchars(str)
|
||
{
|
||
var s = "";
|
||
if (str.length == 0) return "";
|
||
s = str.replace(/&/g, "&");
|
||
s = s.replace(/</g, "<");
|
||
s = s.replace(/>/g, ">");
|
||
s = s.replace(/"/g, """);
|
||
return s;
|
||
}
|
||
|
||
function getColOfScore(score) {
|
||
if (score == 0) {
|
||
return ColorConverter.toStr(ColorConverter.toRGB(new HSV(0, 100, 80)));
|
||
} else if (score == 100) {
|
||
return ColorConverter.toStr(ColorConverter.toRGB(new HSV(120, 100, 80)));
|
||
} else {
|
||
return ColorConverter.toStr(ColorConverter.toRGB(new HSV(30 + score * 60 / 100, 100, 90)));
|
||
}
|
||
}
|
||
|
||
function getUserLink(username, realname) {
|
||
if (!username) {
|
||
return '';
|
||
}
|
||
var text = username;
|
||
if (username.charAt(0) == '@') {
|
||
username = username.substr(1);
|
||
}
|
||
if (realname) {
|
||
text = text + ' <span class="uoj-realname d-inline-block">(' + realname + ')</span>';
|
||
}
|
||
return '<a class="uoj-username" href="' + uojHome + '/user/profile/' + username + '">' + text + '</a>';
|
||
}
|
||
function getUserSpan(username, realname) {
|
||
if (!username) {
|
||
return '';
|
||
}
|
||
var text = username;
|
||
if (username.charAt(0) == '@') {
|
||
username = username.substr(1);
|
||
}
|
||
if (realname) {
|
||
text = text + ' <span class="uoj-realname d-inline-block">(' + realname + ')</span>';
|
||
}
|
||
return '<span class="uoj-username">' + text + '</span>';
|
||
}
|
||
|
||
function replaceWithHighlightUsername() {
|
||
var username = $(this).text();
|
||
var realname = $(this).data("realname");
|
||
if ($(this).data("link") != 0) {
|
||
$(this).replaceWith(getUserLink(username, realname));
|
||
} else {
|
||
$(this).replaceWith(getUserSpan(username, realname));
|
||
}
|
||
}
|
||
|
||
$.fn.uoj_honor = function() {
|
||
return this.each(function() {
|
||
var honor = $(this).text();
|
||
var realname = $(this).data("realname");
|
||
if (realname) {
|
||
honor = honor + ' (' + realname + ')';
|
||
}
|
||
$(this).css('color', '#007bff').html(honor);
|
||
});
|
||
}
|
||
|
||
function showErrorHelp(name, err) {
|
||
if (err) {
|
||
$('#div-' + name).addClass('has-error');
|
||
$('#help-' + name).text(err);
|
||
return false;
|
||
} else {
|
||
$('#div-' + name).removeClass('has-error');
|
||
$('#help-' + name).text('');
|
||
return true;
|
||
}
|
||
}
|
||
function getFormErrorAndShowHelp(name, val) {
|
||
var err = val($('#input-' + name).val());
|
||
return showErrorHelp(name, err);
|
||
}
|
||
|
||
function validateSettingPassword(str) {
|
||
if (str.length < 6) {
|
||
return '密码长度不应小于6。';
|
||
} else if (! /^[!-~]+$/.test(str)) {
|
||
return '密码应只包含可见ASCII字符。';
|
||
} else if (str != $('#input-confirm_password').val()) {
|
||
return '两次输入的密码不一致。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
function validatePassword(str) {
|
||
if (str.length < 6) {
|
||
return '密码长度不应小于6。';
|
||
} else if (! /^[!-~]+$/.test(str)) {
|
||
return '密码应只包含可见ASCII字符。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
function validateEmail(str) {
|
||
if (str.length > 50) {
|
||
return '电子邮箱地址太长。';
|
||
} else if (! /^(.+)@(.+)$/.test(str)) {
|
||
return '电子邮箱地址非法。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
function validateUsername(str) {
|
||
if (str.length == 0) {
|
||
return '用户名不能为空。';
|
||
} else if (! /^[a-zA-Z0-9_]+$/.test(str)) {
|
||
return '用户名应只包含大小写英文字母、数字和下划线。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
function validateQQ(str) {
|
||
if (str.length < 5) {
|
||
return 'QQ的长度不应小于5。';
|
||
} else if (str.length > 15) {
|
||
return 'QQ的长度不应大于15。';
|
||
} else if (/\D/.test(str)) {
|
||
return 'QQ应只包含0~9的数字。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
function validateMotto(str) {
|
||
if (str.length > 1024) {
|
||
return '不能超过 1024 个字符。';
|
||
} else {
|
||
return '';
|
||
}
|
||
}
|
||
|
||
// tags
|
||
$.fn.uoj_problem_tag = function() {
|
||
return this.each(function() {
|
||
$(this).attr('href', uojHome + '/problems?tag=' + encodeURIComponent($(this).text()));
|
||
});
|
||
}
|
||
$.fn.uoj_list_tag = function() {
|
||
return this.each(function() {
|
||
$(this).attr('href', uojHome + '/problem_lists?tag=' + encodeURIComponent($(this).text()));
|
||
});
|
||
}
|
||
$.fn.uoj_blog_tag = function() {
|
||
return this.each(function() {
|
||
$(this).attr('href', uojBlogUrl + '/archive?tag=' + encodeURIComponent($(this).text()));
|
||
});
|
||
}
|
||
|
||
// click zan
|
||
function click_zan(zan_id, zan_type, zan_delta, node) {
|
||
var loading_node = $('<div class="text-muted">loading...</div>');
|
||
$(node).replaceWith(loading_node);
|
||
$.post(zan_link + '/click-zan', {
|
||
id : zan_id,
|
||
delta : zan_delta,
|
||
type : zan_type
|
||
}, function(ret) {
|
||
$(loading_node).replaceWith($(ret).click_zan_block());
|
||
}).fail(function() {
|
||
$(loading_node).replaceWith('<div class="text-danger">failed</div>');
|
||
});
|
||
}
|
||
|
||
$.fn.click_zan_block = function() {
|
||
return this.each(function() {
|
||
var id = $(this).data('id');
|
||
var type = $(this).data('type');
|
||
var val = parseInt($(this).data('val'));
|
||
var cnt = parseInt($(this).data('cnt'));
|
||
if (isNaN(cnt)) {
|
||
return;
|
||
}
|
||
if (val == 1) {
|
||
$(this).addClass('uoj-click-zan-block-cur-up');
|
||
} else if (val == 0) {
|
||
$(this).addClass('uoj-click-zan-block-cur-zero');
|
||
} else if (val == -1) {
|
||
$(this).addClass('uoj-click-zan-block-cur-down');
|
||
} else {
|
||
return;
|
||
}
|
||
if (cnt > 0) {
|
||
$(this).addClass('uoj-click-zan-block-positive');
|
||
} else if (cnt == 0) {
|
||
$(this).addClass('uoj-click-zan-block-neutral');
|
||
} else {
|
||
$(this).addClass('uoj-click-zan-block-negative');
|
||
}
|
||
|
||
var up_icon_html = isBootstrap5Page
|
||
? '<i class="bi bi-hand-thumbs-up"></i>'
|
||
: '<span class="glyphicon glyphicon-thumbs-up"></span>';
|
||
var down_icon_html = isBootstrap5Page
|
||
? '<i class="bi bi-hand-thumbs-down"></i>'
|
||
: '<span class="glyphicon glyphicon-thumbs-down"></span>';
|
||
|
||
var node = this;
|
||
var up_node = $('<a href="#" class="uoj-click-zan-up">'+up_icon_html+uojLocale('click-zan::good')+'</a>').click(function(e) {
|
||
e.preventDefault();
|
||
click_zan(id, type, 1, node);
|
||
}).addClass(isBootstrap5Page ? 'text-decoration-none' : '');
|
||
var down_node = $('<a href="#" class="uoj-click-zan-down">'+down_icon_html+uojLocale('click-zan::bad')+'</a>').click(function(e) {
|
||
e.preventDefault();
|
||
click_zan(id, type, -1, node);
|
||
}).addClass(isBootstrap5Page ? 'text-decoration-none' : '');
|
||
|
||
$(this)
|
||
.append(up_node)
|
||
.append(down_node)
|
||
.append($('<span class="uoj-click-zan-cnt">[<strong>' + (cnt > 0 ? '+' + cnt : cnt) + '</strong>]</span>'));
|
||
});
|
||
}
|
||
|
||
// count down
|
||
function getCountdownStr(t, font_size, color = true) {
|
||
var x = Math.floor(t);
|
||
var ss = toFilledStr(x % 60, '0', 2);
|
||
x = Math.floor(x / 60);
|
||
var mm = toFilledStr(x % 60, '0', 2);
|
||
x = Math.floor(x / 60);
|
||
var hh = x.toString();
|
||
|
||
var res = '<span style="font-size:' + font_size + '">';
|
||
res += '<span '
|
||
if (color) res += ' style="color:' + getColOfScore(Math.min(t / 10800 * 100, 100)) + '" ';
|
||
res += ' >' + hh + '</span>';
|
||
res += ':';
|
||
res += '<span '
|
||
if (color) res += ' style="color:' + getColOfScore(mm / 60 * 100) + '" ';
|
||
res += ' >' + mm + '</span>';
|
||
res += ':';
|
||
res += '<span ';
|
||
if (color) res += ' style="color:' + getColOfScore(ss / 60 * 100) + '" ';
|
||
res +=' >' + ss + '</span>';
|
||
res += '</span>'
|
||
return res;
|
||
}
|
||
|
||
$.fn.countdown = function(rest, callback, font_size = '30px', color = true) {
|
||
return this.each(function() {
|
||
var start = new Date().getTime();
|
||
var cur_rest = rest != undefined ? rest : parseInt($(this).data('rest'));
|
||
var cur = this;
|
||
var countdown = function() {
|
||
var passed = Math.floor((new Date().getTime() - start) / 1000);
|
||
if (passed >= cur_rest) {
|
||
$(cur).html(getCountdownStr(0, font_size, color));
|
||
if (callback != undefined) {
|
||
callback();
|
||
}
|
||
} else {
|
||
$(cur).html(getCountdownStr(cur_rest - passed, font_size, color));
|
||
setTimeout(countdown, 1000);
|
||
}
|
||
}
|
||
countdown();
|
||
});
|
||
};
|
||
|
||
$.fn.uoj_testcase = function() {
|
||
return this.each(function() {
|
||
var id = parseInt($(this).data('test'));
|
||
|
||
var download_html = isBootstrap5Page
|
||
? '<i class="bi bi-download"></i> 下载'
|
||
: '<span class="glyphicon glyphicon-download-alt"></span> 下载';
|
||
|
||
if (id > 0 && typeof problem_id !== 'undefined' && problem_id) {
|
||
$('.uoj-testcase-download-input', this)
|
||
.html(download_html)
|
||
.attr('href', '/download.php?type=testcase&id=' + problem_id + '&testcase_id=' + id + '&testcase_type=input')
|
||
.addClass('btn btn-secondary btn-sm float-right');
|
||
$('.uoj-testcase-download-output', this)
|
||
.html(download_html)
|
||
.attr('href', '/download.php?type=testcase&id=' + problem_id + '&testcase_id=' + id + '&testcase_type=output')
|
||
.addClass('btn btn-secondary btn-sm float-right');
|
||
}
|
||
});
|
||
}
|
||
|
||
// update_judgement_status
|
||
update_judgement_status_list = []
|
||
function update_judgement_status_details(id) {
|
||
update_judgement_status_list.push(id);
|
||
};
|
||
|
||
$(document).ready(function() {
|
||
function update() {
|
||
$.get("/submission-status-details", {
|
||
get: update_judgement_status_list
|
||
},
|
||
function(data) {
|
||
for (var i = 0; i < update_judgement_status_list.length; i++) {
|
||
$("#status_details_" + update_judgement_status_list[i]).html(data[i].html);
|
||
if (data[i].judged) {
|
||
location.reload();
|
||
}
|
||
}
|
||
}, 'json').always(
|
||
function() {
|
||
setTimeout(update, 500);
|
||
}
|
||
);
|
||
}
|
||
if (update_judgement_status_list.length > 0) {
|
||
setTimeout(update, 500);
|
||
}
|
||
});
|
||
|
||
// highlight
|
||
$.fn.uoj_highlight = function() {
|
||
return $(this).each(function() {
|
||
$(this).find("span.uoj-username").each(replaceWithHighlightUsername);
|
||
$(this).find(".uoj-honor").uoj_honor();
|
||
$(this).find(".uoj-testcase").uoj_testcase();
|
||
$(this).find(".uoj-score").each(function() {
|
||
var score = parseInt($(this).text());
|
||
var maxscore = parseInt($(this).data('max'));
|
||
if (isNaN(score)) {
|
||
return;
|
||
}
|
||
if (isNaN(maxscore)) {
|
||
$(this).css("color", getColOfScore(score));
|
||
} else {
|
||
$(this).css("color", getColOfScore(score / maxscore * 100));
|
||
}
|
||
});
|
||
$(this).find(".uoj-status").each(function() {
|
||
var success = parseInt($(this).data("success"));
|
||
if(isNaN(success)){
|
||
return;
|
||
}
|
||
if (success == 1) {
|
||
$(this).css("color", ColorConverter.toStr(ColorConverter.toRGB(new HSV(120, 100, 80))));
|
||
}
|
||
else {
|
||
$(this).css("color", ColorConverter.toStr(ColorConverter.toRGB(new HSV(0, 100, 100))));
|
||
}
|
||
});
|
||
$(this).find(".uoj-problem-tag").uoj_problem_tag();
|
||
$(this).find(".uoj-list-tag").uoj_list_tag();
|
||
$(this).find(".uoj-blog-tag").uoj_blog_tag();
|
||
$(this).find(".uoj-click-zan-block").click_zan_block();
|
||
$(this).find(".countdown").countdown();
|
||
$(this).find(".uoj-readmore").readmore({
|
||
moreLink: '<a href="#" class="text-right">more...</a>',
|
||
lessLink: '<a href="#" class="text-right">close</a>',
|
||
});
|
||
});
|
||
};
|
||
|
||
$(document).ready(function() {
|
||
$('body').uoj_highlight();
|
||
});
|
||
|
||
// contest notice
|
||
function checkContestNotice(id, lastTime) {
|
||
$.post('/contest/' + id.toString(), {
|
||
check_notice : '',
|
||
last_time : lastTime
|
||
},
|
||
function(data) {
|
||
setTimeout(function() {
|
||
checkContestNotice(id, data.time);
|
||
}, 60000);
|
||
if (data.msg != undefined) {
|
||
var len=data.msg.length;
|
||
for (var i=0;i<len;i++) alert(data.msg[i]);
|
||
}
|
||
},
|
||
'json'
|
||
).fail(function() {
|
||
setTimeout(function() {
|
||
checkContestNotice(id, lastTime);
|
||
}, 60000);
|
||
});
|
||
}
|
||
|
||
// long table
|
||
$.fn.long_table = function(data, cur_page, header_row, get_row_str, config) {
|
||
return this.each(function() {
|
||
var table_div = this;
|
||
|
||
$(table_div).html('');
|
||
|
||
var page_len = config.page_len != undefined ? config.page_len : 10;
|
||
|
||
if (!config.echo_full) {
|
||
var n_rows = data.length;
|
||
var n_pages = Math.max(Math.ceil(n_rows / page_len), 1);
|
||
if (cur_page == undefined) {
|
||
cur_page = 1;
|
||
}
|
||
if (cur_page < 1) {
|
||
cur_page = 1;
|
||
} else if (cur_page > n_pages) {
|
||
cur_page = n_pages;
|
||
}
|
||
var cur_start = (cur_page - 1) * page_len;
|
||
} else {
|
||
var n_rows = data.length;
|
||
var n_pages = 1;
|
||
cur_page = 1;
|
||
var cur_start = (cur_page - 1) * page_len;
|
||
}
|
||
|
||
var div_classes = config.div_classes != undefined ? config.div_classes : ['table-responsive'];
|
||
var table_classes = config.table_classes != undefined ? config.table_classes : ['table', 'table-bordered', 'table-hover', 'table-striped', 'table-text-center'];
|
||
|
||
var now_cnt = 0;
|
||
var tbody = $('<tbody />')
|
||
for (var i = 0; i < page_len && cur_start + i < n_rows; i++) {
|
||
now_cnt++;
|
||
if (config.get_row_index) {
|
||
tbody.append(get_row_str(data[cur_start + i], cur_start + i));
|
||
} else {
|
||
tbody.append(get_row_str(data[cur_start + i]));
|
||
}
|
||
}
|
||
if (now_cnt == 0) {
|
||
tbody.append('<tr><td colspan="233">无</td></tr>');
|
||
}
|
||
|
||
$(table_div).append(
|
||
$('<div class="' + div_classes.join(' ') + '" />').append(
|
||
$('<table class="' + table_classes.join(' ') + '" />').append(
|
||
$('<thead>' + header_row + '</thead>')
|
||
).append(
|
||
tbody
|
||
)
|
||
)
|
||
);
|
||
|
||
if (config.print_after_table != undefined) {
|
||
$(table_div).append(config.print_after_table());
|
||
}
|
||
|
||
var get_page_li = function(p, h) {
|
||
if (p == -1) {
|
||
return $('<li class="page-item"></li>').addClass('disabled').append($('<a class="page-link"></a>').append(h));
|
||
}
|
||
|
||
var li = $('<li class="page-item"></li>');
|
||
if (p == cur_page) {
|
||
li.addClass('active');
|
||
}
|
||
li.append(
|
||
$('<a class="page-link"></a>').attr('href', '#' + table_div.id).append(h).click(function(e) {
|
||
if (config.prevent_focus_on_click) {
|
||
e.preventDefault();
|
||
}
|
||
$(table_div).long_table(data, p, header_row, get_row_str, config);
|
||
})
|
||
);
|
||
return li;
|
||
};
|
||
|
||
if (n_pages > 1) {
|
||
var pagination = $('<ul class="pagination top-buffer-no bot-buffer-sm justify-content-center"></ul>');
|
||
if (cur_page > 1) {
|
||
pagination.append(get_page_li(cur_page - 1, '<span class="glyphicon glyphicon glyphicon-backward"></span>'));
|
||
} else {
|
||
pagination.append(get_page_li(-1, '<span class="glyphicon glyphicon glyphicon-backward"></span>'));
|
||
}
|
||
var max_extend = config.max_extend != undefined ? config.max_extend : 5;
|
||
for (var i = Math.max(cur_page - max_extend, 1); i <= Math.min(cur_page + max_extend, n_pages); i++) {
|
||
pagination.append(get_page_li(i, i.toString()));
|
||
}
|
||
if (cur_page < n_pages) {
|
||
pagination.append(get_page_li(cur_page + 1, '<span class="glyphicon glyphicon glyphicon-forward"></span>'));
|
||
} else {
|
||
pagination.append(get_page_li(-1, '<span class="glyphicon glyphicon glyphicon-forward"></span>'));
|
||
}
|
||
$(table_div).append($('<div class="text-center"></div>').append(pagination));
|
||
}
|
||
});
|
||
};
|
||
|
||
// code mirror
|
||
function require_codemirror(config, callback) {
|
||
if ($('link[href="' + uojHome + '/js/codemirror/lib/codemirror.css' + '"]').length == 0) {
|
||
$('<link type="text/css" rel="stylesheet" href="' + uojHome + '/js/codemirror/lib/codemirror.css' + '" />').appendTo('head');
|
||
}
|
||
$LAB.script(uojHome + '/js/codemirror/lib/codemirror.js')
|
||
.wait()
|
||
.script(uojHome + '/js/codemirror/addon/mode/overlay.js')
|
||
.script(uojHome + '/js/codemirror/addon/selection/active-line.js')
|
||
.wait(callback)
|
||
}
|
||
|
||
function get_codemirror_mode(lang) {
|
||
switch (lang) {
|
||
case 'C++':
|
||
case 'C++11':
|
||
case 'C++17':
|
||
case 'C++98':
|
||
return 'text/x-c++src';
|
||
case 'C':
|
||
return 'text/x-csrc';
|
||
case 'Python2':
|
||
case 'Python3':
|
||
return 'text/x-python';
|
||
case 'Pascal':
|
||
return 'text/x-pascal';
|
||
case 'text':
|
||
return 'text/plain';
|
||
default:
|
||
return 'text/plain';
|
||
}
|
||
};
|
||
function require_codemirror_mode(mode, callback) {
|
||
var name = 'none';
|
||
switch (mode) {
|
||
case 'text/x-c++src':
|
||
case 'text/x-csrc':
|
||
name = 'clike';
|
||
break;
|
||
case 'text/x-python':
|
||
name = 'python';
|
||
break;
|
||
case 'text/x-pascal':
|
||
name = 'pascal';
|
||
break;
|
||
}
|
||
if (name !== 'none') {
|
||
$LAB.script(uojHome + '/js/codemirror/mode/' + name + '/' + name + '.js')
|
||
.wait(callback);
|
||
} else {
|
||
setTimeout(callback, 0);
|
||
}
|
||
};
|
||
|
||
// auto save
|
||
function autosave_locally(interval, name, target) {
|
||
if (typeof(Storage) === "undefined") {
|
||
console.log('autosave_locally: Sorry! No Web Storage support..');
|
||
return;
|
||
}
|
||
var url = window.location.href;
|
||
var hp = url.indexOf('#');
|
||
var uri = hp == -1 ? url : url.substr(0, hp);
|
||
var full_name = name + '@' + uri;
|
||
|
||
target.val(localStorage.getItem(full_name));
|
||
var save = function() {
|
||
localStorage.setItem(full_name, target.val());
|
||
setTimeout(save, interval);
|
||
};
|
||
setTimeout(save, interval);
|
||
}
|
||
|
||
// source code form group
|
||
$.fn.source_code_form_group = function(name, text, langs_options_html) {
|
||
return this.each(function() {
|
||
var input_language_id = 'input-' + name + '_language';
|
||
var input_language_name = name + '_language';
|
||
var input_upload_type_name = name + '_upload_type';
|
||
var input_editor_id = 'input-' + name + '_editor';
|
||
var input_editor_name = name + '_editor';
|
||
var input_file_id = 'input-' + name + '_file';
|
||
var input_file_name = name + '_file';
|
||
|
||
var div_help_language_id = 'div-help-' + name + '_language';
|
||
var div_editor_id = 'div-' + name + '_editor';
|
||
var div_file_id = 'div-' + name + '_file';
|
||
|
||
var help_file_id = 'help-' + name + '_file';
|
||
|
||
var input_language =
|
||
$('<select id="' + input_language_id + '" name="' + input_language_name + '" class="form-control input-sm form-select"/>')
|
||
.html(langs_options_html);
|
||
var input_upload_type_editor = $('<input type="radio" name="' + input_upload_type_name + '" value="editor" />');
|
||
var input_upload_type_file = $('<input type="radio" name="' + input_upload_type_name + '" value="file" />');
|
||
var input_file = $('<input type="file" id="' + input_file_id + '" name="' + input_file_name + '" style="display: none" />');
|
||
var input_file_path = $('<input class="form-control" type="text" readonly="readonly" />');
|
||
var input_editor = $('<textarea class="form-control" id="' + input_editor_id + '" name="' + input_editor_name + '"></textarea>');
|
||
var input_use_advanced_editor = $('<input type="checkbox">');
|
||
|
||
var div_editor =
|
||
$('<div id="' + div_editor_id + '" class="col-sm-12"/>')
|
||
.append(input_editor)
|
||
.append($('<div class="checkbox text-right" />')
|
||
.append($('<label />')
|
||
.append(input_use_advanced_editor)
|
||
.append(' ' + uojLocale('editor::use advanced editor'))
|
||
)
|
||
)
|
||
var div_file =
|
||
$('<div id="' + div_file_id + '" class="col-sm-12"/>')
|
||
.append(input_file)
|
||
.append($('<div class="input-group"/>')
|
||
.append(input_file_path)
|
||
.append($('<span class="input-group-append"/>')
|
||
.append($('<button type="button" class="btn btn-primary">'+'<span class="glyphicon glyphicon-folder-open"></span> '+uojLocale('editor::browse')+'</button>')
|
||
.css('width', '100px')
|
||
.click(function() {
|
||
input_file.click();
|
||
})
|
||
)
|
||
)
|
||
)
|
||
.append($('<span class="help-block" id="' + help_file_id + '"></span>'))
|
||
var div_help_language = $('<div id="' + div_help_language_id + '" class="col-sm-12 text-warning top-buffer-sm">');
|
||
|
||
var advanced_editor = null;
|
||
var advanced_editor_init = function() {
|
||
require_codemirror({}, function() {
|
||
var mode = get_codemirror_mode(input_language.val());
|
||
require_codemirror_mode(mode, function() {
|
||
if (advanced_editor != null) {
|
||
return;
|
||
}
|
||
advanced_editor = CodeMirror.fromTextArea(input_editor[0], {
|
||
mode: mode,
|
||
lineNumbers: true,
|
||
matchBrackets: true,
|
||
lineWrapping: true,
|
||
styleActiveLine: true,
|
||
indentUnit: 4,
|
||
indentWithTabs: true,
|
||
theme: 'default'
|
||
});
|
||
advanced_editor.on('change', function() {
|
||
advanced_editor.save();
|
||
});
|
||
$(advanced_editor.getWrapperElement()).css('box-shadow', '0 2px 10px rgba(0,0,0,0.2)');
|
||
advanced_editor.focus();
|
||
});
|
||
});
|
||
}
|
||
|
||
var save_prefer_upload_type = function(type) {
|
||
$.cookie('uoj_source_code_form_group_preferred_upload_type', type, { expires: 7, path: '/' });
|
||
};
|
||
|
||
autosave_locally(2000, name, input_editor);
|
||
|
||
var prefer_upload_type = $.cookie('uoj_source_code_form_group_preferred_upload_type');
|
||
if (prefer_upload_type === null) {
|
||
prefer_upload_type = 'editor';
|
||
}
|
||
if (prefer_upload_type == 'file') {
|
||
input_upload_type_file[0].checked = true;
|
||
div_editor.css('display', 'none');
|
||
} else {
|
||
input_upload_type_editor[0].checked = true;
|
||
div_file.css('display', 'none');
|
||
|
||
if (prefer_upload_type == 'advanced') {
|
||
input_use_advanced_editor[0].checked = true;
|
||
}
|
||
}
|
||
|
||
input_language.change(function() {
|
||
if (advanced_editor != null) {
|
||
var mode = get_codemirror_mode(input_language.val());
|
||
require_codemirror_mode(mode, function() {
|
||
if (mode != get_codemirror_mode(input_language.val())) {
|
||
return;
|
||
}
|
||
advanced_editor.setOption('mode', mode);
|
||
});
|
||
}
|
||
})
|
||
input_upload_type_editor.click(function() {
|
||
div_editor.show('fast');
|
||
div_file.hide('fast');
|
||
save_prefer_upload_type('editor');
|
||
});
|
||
input_upload_type_file.click(function() {
|
||
div_file.show('fast');
|
||
div_editor.hide('fast');
|
||
save_prefer_upload_type('file');
|
||
});
|
||
input_file.change(function() {
|
||
input_file_path.val(input_file.val());
|
||
});
|
||
input_use_advanced_editor.click(function() {
|
||
if (this.checked) {
|
||
advanced_editor_init();
|
||
save_prefer_upload_type('advanced');
|
||
} else {
|
||
if (advanced_editor != null) {
|
||
advanced_editor.toTextArea();
|
||
advanced_editor = null;
|
||
input_editor.focus();
|
||
}
|
||
save_prefer_upload_type('editor');
|
||
}
|
||
});
|
||
|
||
$(this)
|
||
.append($('<div class="row col-sm-12"/>')
|
||
.append($('<label class="col-sm-2 control-label"><div class="'+(isBootstrap5Page ? ' text-start ' : ' text-left ')+'">' + text + '</div></label>'))
|
||
.append($('<label class="col-sm-1 control-label '+ (isBootstrap5Page ? ' px-1 ' : '') +' " for="' + input_language_name + '">'+uojLocale('editor::language')+'</label>'))
|
||
.append($('<div class="col-sm-2"/>')
|
||
.append(input_language)
|
||
)
|
||
.append($('<div class="col-sm-2 offset-sm-3 radio"/>')
|
||
.append($('<label/>')
|
||
.append(input_upload_type_editor)
|
||
.append(' '+uojLocale('editor::upload by editor'))
|
||
)
|
||
)
|
||
.append($('<div class="col-sm-2 radio"/>')
|
||
.append($('<label/>')
|
||
.append(input_upload_type_file)
|
||
.append(' '+uojLocale('editor::upload from local'))
|
||
)
|
||
))
|
||
.append(div_help_language)
|
||
.append(div_editor)
|
||
.append(div_file);
|
||
|
||
if (prefer_upload_type == 'advanced') {
|
||
var check_advanced_init = function() {
|
||
if (div_editor.is(':visible')) {
|
||
advanced_editor_init();
|
||
} else {
|
||
setTimeout(check_advanced_init, 1);
|
||
}
|
||
}
|
||
check_advanced_init();
|
||
}
|
||
});
|
||
}
|
||
|
||
// text file form group
|
||
$.fn.text_file_form_group = function(name, text) {
|
||
return this.each(function() {
|
||
var input_upload_type_name = name + '_upload_type';
|
||
var input_editor_id = 'input-' + name + '_editor';
|
||
var input_editor_name = name + '_editor';
|
||
var input_file_id = 'input-' + name + '_file';
|
||
var input_file_name = name + '_file';
|
||
|
||
var div_editor_id = 'div-' + name + '_editor';
|
||
var div_file_id = 'div-' + name + '_file';
|
||
|
||
var help_file_id = 'help-' + name + '_file';
|
||
|
||
var input_upload_type_editor = $('<input type="radio" name="' + input_upload_type_name + '" value="editor" />');
|
||
var input_upload_type_file = $('<input type="radio" name="' + input_upload_type_name + '" value="file" />');
|
||
var input_file = $('<input type="file" id="' + input_file_id + '" name="' + input_file_name + '" style="display: none" />');
|
||
var input_file_path = $('<input class="form-control" type="text" readonly="readonly" />');
|
||
var input_editor = $('<textarea class="form-control" id="' + input_editor_id + '" name="' + input_editor_name + '"></textarea>');
|
||
var input_use_advanced_editor = $('<input type="checkbox">');
|
||
|
||
var div_editor =
|
||
$('<div id="' + div_editor_id + '" class="col-sm-12"/>')
|
||
.append(input_editor)
|
||
.append($('<div class="checkbox text-right" />')
|
||
.append($('<label />')
|
||
.append(input_use_advanced_editor)
|
||
.append(' ' + uojLocale('editor::use advanced editor'))
|
||
)
|
||
)
|
||
var div_file =
|
||
$('<div id="' + div_file_id + '" class="col-sm-12"/>')
|
||
.append(input_file)
|
||
.append($('<div class="input-group"/>')
|
||
.append(input_file_path)
|
||
.append($('<div class="input-group-append"/>')
|
||
.append($('<button type="button" class="btn btn-primary">'+'<span class="glyphicon glyphicon-folder-open"></span> '+uojLocale('editor::browse')+'</button>')
|
||
.css('width', '100px')
|
||
.click(function() {
|
||
input_file.click();
|
||
})
|
||
)
|
||
)
|
||
)
|
||
.append($('<span class="help-block" id="' + help_file_id + '"></span>'))
|
||
|
||
var advanced_editor = null;
|
||
var advanced_editor_init = function() {
|
||
require_codemirror({}, function() {
|
||
var mode = get_codemirror_mode('text');
|
||
require_codemirror_mode(mode, function() {
|
||
if (advanced_editor != null) {
|
||
return;
|
||
}
|
||
advanced_editor = CodeMirror.fromTextArea(input_editor[0], {
|
||
mode: mode,
|
||
lineNumbers: true,
|
||
matchBrackets: true,
|
||
lineWrapping: true,
|
||
styleActiveLine: true,
|
||
indentUnit: 4,
|
||
indentWithTabs: true,
|
||
theme: 'default'
|
||
});
|
||
advanced_editor.on('change', function() {
|
||
advanced_editor.save();
|
||
});
|
||
$(advanced_editor.getWrapperElement()).css('box-shadow', '0 2px 10px rgba(0,0,0,0.2)');
|
||
advanced_editor.focus();
|
||
});
|
||
});
|
||
}
|
||
|
||
var save_prefer_upload_type = function(type) {
|
||
$.cookie('uoj_text_file_form_group_preferred_upload_type', type, { expires: 7, path: '/' });
|
||
};
|
||
|
||
autosave_locally(2000, name, input_editor);
|
||
|
||
var prefer_upload_type = $.cookie('uoj_text_file_form_group_preferred_upload_type');
|
||
if (prefer_upload_type === null) {
|
||
prefer_upload_type = 'editor';
|
||
}
|
||
if (prefer_upload_type == 'file') {
|
||
input_upload_type_file[0].checked = true;
|
||
div_editor.css('display', 'none');
|
||
} else {
|
||
input_upload_type_editor[0].checked = true;
|
||
div_file.css('display', 'none');
|
||
|
||
if (prefer_upload_type == 'advanced') {
|
||
input_use_advanced_editor[0].checked = true;
|
||
}
|
||
}
|
||
|
||
input_upload_type_editor.click(function() {
|
||
div_editor.show('fast');
|
||
div_file.hide('fast');
|
||
save_prefer_upload_type('editor');
|
||
});
|
||
input_upload_type_file.click(function() {
|
||
div_file.show('fast');
|
||
div_editor.hide('fast');
|
||
save_prefer_upload_type('file');
|
||
});
|
||
input_file.change(function() {
|
||
input_file_path.val(input_file.val());
|
||
});
|
||
input_use_advanced_editor.click(function() {
|
||
if (this.checked) {
|
||
advanced_editor_init();
|
||
save_prefer_upload_type('advanced');
|
||
} else {
|
||
if (advanced_editor != null) {
|
||
advanced_editor.toTextArea();
|
||
advanced_editor = null;
|
||
input_editor.focus();
|
||
}
|
||
save_prefer_upload_type('editor');
|
||
}
|
||
});
|
||
|
||
$(this)
|
||
.append($('<div class="row"/>')
|
||
.append($('<label class="col-sm-2 control-label"><div class="text-left">' + text + '</div></label>'))
|
||
.append($('<div class="top-buffer-sm" />'))
|
||
.append($('<div class="col-sm-2 offset-sm-6 radio"/>')
|
||
.append($('<label/>')
|
||
.append(input_upload_type_editor)
|
||
.append(' '+uojLocale('editor::upload by editor'))
|
||
)
|
||
)
|
||
.append($('<div class="col-sm-2 radio"/>')
|
||
.append($('<label/>')
|
||
.append(input_upload_type_file)
|
||
.append(' '+uojLocale('editor::upload from local'))
|
||
)
|
||
))
|
||
.append(div_editor)
|
||
.append(div_file);
|
||
|
||
if (prefer_upload_type == 'advanced') {
|
||
var check_advanced_init = function() {
|
||
if (div_editor.is(':visible')) {
|
||
advanced_editor_init();
|
||
} else {
|
||
setTimeout(check_advanced_init, 1);
|
||
}
|
||
}
|
||
check_advanced_init();
|
||
}
|
||
});
|
||
}
|
||
|
||
// custom test
|
||
function custom_test_onsubmit(response_text, div_result, url) {
|
||
if (response_text != '') {
|
||
$(div_result).html('<div class="text-danger">' + response_text + '</div>');
|
||
return;
|
||
}
|
||
var update = function() {
|
||
var can_next = true;
|
||
$.get(url,
|
||
function(data) {
|
||
if (data.judged === undefined) {
|
||
$(div_result).html('<div class="text-danger">error</div>');
|
||
} else {
|
||
var judge_status = $('<table class="table table-bordered table-text-center"><tr class="info">' + data.html + '</tr></table>');
|
||
$(div_result).empty();
|
||
$(div_result).append(judge_status);
|
||
if (data.judged) {
|
||
var judge_result = $(data.result);
|
||
judge_result.css('display', 'none');
|
||
$(div_result).append(judge_result);
|
||
judge_status.hide(500);
|
||
judge_result.slideDown(500);
|
||
can_next = false;
|
||
}
|
||
}
|
||
}, 'json')
|
||
.always(function() {
|
||
if (can_next) {
|
||
setTimeout(update, 500);
|
||
}
|
||
});
|
||
};
|
||
setTimeout(update, 500);
|
||
}
|
||
|
||
// comment
|
||
function showCommentReplies(id, replies) {
|
||
var toggleFormReply = function(from, text) {
|
||
if (text == undefined) {
|
||
text = '';
|
||
}
|
||
|
||
var p = '#comment-body-' + id;
|
||
var q = '#div-form-reply';
|
||
var r = '#input-reply_comment';
|
||
var t = '#input-reply_id';
|
||
if ($(q).data('from') != from) {
|
||
$(q).data('from', from);
|
||
$(q).hide('fast', function() {
|
||
$(this).appendTo(p).show('fast', function() {
|
||
$(t).val(id);
|
||
$(r).val(text).focus();
|
||
});
|
||
});
|
||
|
||
} else if ($(q).css('display') != 'none') {
|
||
$(q).appendTo(p).hide('fast');
|
||
} else {
|
||
$(q).appendTo(p).show('fast', function() {
|
||
$(t).val(id);
|
||
$(r).val(text).focus();
|
||
});
|
||
}
|
||
}
|
||
|
||
$('#reply-to-' + id).click(function(e) {
|
||
e.preventDefault();
|
||
toggleFormReply(id);
|
||
});
|
||
|
||
if (replies.length == 0) {
|
||
return;
|
||
}
|
||
|
||
$("#replies-" + id).long_table(
|
||
replies,
|
||
1,
|
||
'<tr>' +
|
||
'<th>评论回复</th>' +
|
||
'</tr>',
|
||
function(reply) {
|
||
return $('<tr id="' + 'comment-' + reply.id + '" />').append(
|
||
$('<td />').append(
|
||
$('<div class="comtbox6">' + getUserLink(reply.poster, reply.poster_realname) + ':' + reply.content + '</div>')
|
||
).append(
|
||
$('<ul class="text-right list-inline bot-buffer-no" />').append(
|
||
'<li>' + '<small class="text-muted">' + reply.post_time + '</small>' + '</li>'
|
||
).append(
|
||
$('<li />').append(
|
||
$('<a href="#">回复</a>').click(function (e) {
|
||
e.preventDefault();
|
||
toggleFormReply(reply.id, '回复 @' + reply.poster + ':');
|
||
})
|
||
)
|
||
)
|
||
)
|
||
).uoj_highlight();
|
||
}, {
|
||
table_classes: ['table', 'table-condensed'],
|
||
page_len: 5,
|
||
prevent_focus_on_click: true
|
||
}
|
||
);
|
||
}
|
||
|
||
// standings
|
||
function showStandings() {
|
||
$("#standings").long_table(
|
||
standings,
|
||
1,
|
||
'<tr>' +
|
||
'<th style="width:' + (show_self_reviews ? '2' : '5') + 'em">#</th>' +
|
||
'<th style="width:' + (show_self_reviews ? '8' : '14') + 'em">'+uojLocale('username')+'</th>' +
|
||
'<th style="width:5em">'+uojLocale('contests::total score')+'</th>' +
|
||
$.map(problems, function(col, idx) {
|
||
return '<th style="width:' + (show_self_reviews ? '10' : '8') + 'em;">' + '<a href="/contest/' + contest_id + '/problem/' + col + '">' + String.fromCharCode('A'.charCodeAt(0) + idx) + '</a>' + '</th>';
|
||
}).join('') +
|
||
(show_self_reviews ? '<th style="width:16em;">赛后总结</th>' : '') +
|
||
'</tr>',
|
||
function(row) {
|
||
var col_tr = '<tr>';
|
||
col_tr += '<td>' + row[3] + '</td>';
|
||
col_tr += '<td>' + getUserLink(row[2][0], row[2][1]) + '</td>';
|
||
col_tr += '<td>' + '<div><span class="uoj-score" data-max="' + problems.length * 100 + '" style="color:' + getColOfScore(row[0] / problems.length) + '">' + row[0] + '</span></div>' + '<div>' + (row[1] == 0 ? '(未提交)' : getPenaltyTimeStr(row[1])) + '</div></td>';
|
||
for (var i = 0; i < problems.length; i++) {
|
||
col_tr += '<td' + (show_self_reviews ? ' style="vertical-align: text-top"' : '') + '>';
|
||
col = score[row[2][0]][i];
|
||
if (col != undefined) {
|
||
col_tr += '<div>';
|
||
|
||
if (col[2]) col_tr += '<a href="/submission/' + col[2] + '" class="uoj-score" style="color:' + getColOfScore(col[0]) + '">' + col[0] + '</a>';
|
||
else col_tr += '<span class="uoj-score" style="color:' + getColOfScore(col[0]) + '">' + col[0] + '</span>';
|
||
|
||
col_tr += '</div>';
|
||
if (show_self_reviews) {
|
||
col_tr += '<div id="review-' + row[2][0] + '-' + i + '"></div>'
|
||
+ '<script>'
|
||
+ '(function() {'
|
||
+ 'var purify_result = DOMPurify.sanitize(decodeURIComponent("' + encodeURIComponent(String(col[3] || '')) + '"), {ALLOWED_TAGS: ["a", "b", "i", "u", "em", "strong", "sub", "sup", "small", "del", "br"], ALLOWED_ATTR: ["href"]});'
|
||
+ '$("#review-' + row[2][0] + '-' + i + '")'
|
||
+ '.html(purify_result ? \'<div class="mt-2 pt-2 border-top">\' + purify_result + \'</div>\' : \'\'); })();'
|
||
+ '</scr' + 'ipt>';
|
||
} else {
|
||
if (standings_version < 2) {
|
||
col_tr += '<div>' + getPenaltyTimeStr(col[1]) + '</div>';
|
||
} else {
|
||
if (col[0] > 0) {
|
||
col_tr += '<div>' + getPenaltyTimeStr(col[1]) + '</div>';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
col_tr += '</td>';
|
||
}
|
||
|
||
if (show_self_reviews) {
|
||
col_tr += '<td><div id="review-' + row[2][0] + '"></div>'
|
||
+ '<script>'
|
||
+ '(function() { $("#review-' + row[2][0] + '")'
|
||
+ '.html(DOMPurify.sanitize(decodeURIComponent("' + encodeURIComponent(String(row[4] || '')) + '"), {ALLOWED_TAGS: ["a", "b", "i", "u", "em", "strong", "sub", "sup", "small", "del", "br"], ALLOWED_ATTR: ["href"]})); })();'
|
||
+ '</scr' + 'ipt></td>';
|
||
}
|
||
col_tr += '</tr>';
|
||
return col_tr;
|
||
}, {
|
||
table_classes: ['table', 'table-bordered', 'table-striped', 'table-text-center', 'table-vertical-middle', 'table-condensed'],
|
||
page_len: 100,
|
||
print_after_table: function() {
|
||
return '<div class="text-right text-muted">' + uojLocale("contests::n participants", standings.length) + '</div><script>if (window.MathJax) window.MathJax.typeset();</scr' + 'ipt>';
|
||
}
|
||
}
|
||
);
|
||
}
|