S2OJ/web/js/uoj.js

1171 lines
35 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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, "&amp;");
s = s.replace(/</g, "&lt;");
s = s.replace(/>/g, "&gt;");
s = s.replace(/"/g, "&quot;");
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(isBootstrap5Page ? 'has-validation' : 'has-error');
if (isBootstrap5Page) $('#div-' + name + ' .form-floating, #input-' + name).addClass('is-invalid');
$('#help-' + name).text(err);
return false;
} else {
$('#div-' + name).removeClass(isBootstrap5Page ? 'has-validation' : 'has-error');
if (isBootstrap5Page) $('#div-' + name+ ' .form-floating, #input-' + name).removeClass('is-invalid');
$('#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="uoj-click-zan-block text-muted">loading...</div>');
var show_text = Boolean($(node).data('show-text'));
$(node).replaceWith(loading_node);
$.post(zan_link + '/click-zan', {
id : zan_id,
delta : zan_delta,
type : zan_type,
'show-text': show_text,
}, function(ret) {
$(loading_node).replaceWith($(ret).click_zan_block());
}).fail(function() {
$(loading_node).replaceWith('<div class="uoj-click-zan-block 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'));
var show_text = Boolean($(this).data('show-text'));
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+(show_text ? 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+(show_text ? 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++20':
case 'C++98':
case 'C++03':
return 'text/x-c++src';
case 'C':
return 'text/x-csrc';
case 'Python2':
case 'Python2.7':
case 'Python3':
return 'text/x-python';
case 'Pascal':
return 'text/x-pascal';
case 'Java8':
case 'Java11':
case 'Java17':
return 'text/x-java';
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-4 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-1 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-4 control-label"><div class="'+(isBootstrap5Page ? ' text-start ' : ' text-left ')+'">' + text + '</div></label>'))
.append($('<div class="col-sm-2 offset-sm-4 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="' + (isBootstrap5Page ? 'text-end mb-0' : 'text-right bot-buffer-no') + ' list-inline" />').append(
'<li>' + '<small class="text-muted">' + reply.post_time + '</small>' + '</li>'
).append(
$('<li />').append(
$('<a class=" ' + (isBootstrap5Page ? ' text-decoration-none ' : '') + ' " 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 + '" class="text-decoration-none">' + 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 += col[3] ? '<div class="mt-2 pt-2 border-top">' + col[3] + '</div>' : '';
} 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;
}, {
div_classes: ['table-responsive'],
table_classes: ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'uoj-standings-table', 'mb-0'],
page_len: 100,
print_after_table: function() {
return '<div class="card-footer bg-transparent text-end text-muted">' + uojLocale("contests::n participants", standings.length) + '</div><script>if (window.MathJax) window.MathJax.typeset();</scr' + 'ipt>';
}
}
);
}