mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core&ui: fix sidebar preview (#491)
Co-authored-by: panda <panda_dtdyy@outlook.com>
This commit is contained in:
1 parent
feb3b5cecb
commit
feb5180476
19 files changed
+152
-244
No files matched your search
@@ -671,19 +671,23 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
|
|||||||
@param('testdata', Types.Boolean)
|
@param('testdata', Types.Boolean)
|
||||||
@param('additional_file', Types.Boolean)
|
@param('additional_file', Types.Boolean)
|
||||||
@param('pjax', Types.Boolean)
|
@param('pjax', Types.Boolean)
|
||||||
async get(domainId: string, getTestdata = true, getAdditionalFile = true, pjax = false) {
|
@param('sidebar', Types.Boolean)
|
||||||
|
async get(domainId: string, getTestdata = true, getAdditionalFile = true, pjax = false, sidebar = false) {
|
||||||
this.response.body.testdata = getTestdata ? sortFiles(this.pdoc.data || []) : [];
|
this.response.body.testdata = getTestdata ? sortFiles(this.pdoc.data || []) : [];
|
||||||
this.response.body.reference = getTestdata ? this.pdoc.reference : '';
|
this.response.body.reference = getTestdata ? this.pdoc.reference : '';
|
||||||
this.response.body.additional_file = getAdditionalFile ? sortFiles(this.pdoc.additional_file || []) : [];
|
this.response.body.additional_file = getAdditionalFile ? sortFiles(this.pdoc.additional_file || []) : [];
|
||||||
if (pjax) {
|
if (pjax) {
|
||||||
const { testdata, additional_file } = this.response.body;
|
const { testdata, additional_file } = this.response.body;
|
||||||
const owner = await user.getById(domainId, this.pdoc.owner);
|
const owner = await user.getById(domainId, this.pdoc.owner);
|
||||||
|
const args = {
|
||||||
|
testdata, additional_file, pdoc: this.pdoc, owner_udoc: owner, sidebar,
|
||||||
|
};
|
||||||
|
const tasks = [];
|
||||||
|
if (getTestdata) tasks.push(this.renderHTML('partials/problem_files.html', { ...args, filetype: 'testdata' }));
|
||||||
|
if (getAdditionalFile) tasks.push(this.renderHTML('partials/problem_files.html', { ...args, filetype: 'additional_file' }));
|
||||||
|
if (!sidebar) tasks.push(this.renderHTML('partials/problem-sidebar-information.html', args));
|
||||||
this.response.body = {
|
this.response.body = {
|
||||||
fragments: (await Promise.all([
|
fragments: (await Promise.all(tasks)).map((i) => ({ html: i })),
|
||||||
this.renderHTML('partials/problem_files-testdata.html', { testdata, pdoc: this.pdoc }),
|
|
||||||
this.renderHTML('partials/problem_files-additional_file.html', { additional_file, pdoc: this.pdoc }),
|
|
||||||
this.renderHTML('partials/problem-sidebar-information.html', { pdoc: this.pdoc, owner_udoc: owner }),
|
|
||||||
])).map((i) => ({ html: i })),
|
|
||||||
};
|
};
|
||||||
this.response.template = '';
|
this.response.template = '';
|
||||||
} else this.response.template = 'problem_files.html';
|
} else this.response.template = 'problem_files.html';
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const Types: Types = {
|
|||||||
Float: [(v) => +v, (v) => Number.isFinite(+v)],
|
Float: [(v) => +v, (v) => Number.isFinite(+v)],
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
ObjectID: [(v) => new ObjectID(v), ObjectID.isValid],
|
ObjectID: [(v) => new ObjectID(v), ObjectID.isValid],
|
||||||
Boolean: [(v) => !!v, null, true],
|
Boolean: [(v) => v && !['false', 'off'].includes(v), null, true],
|
||||||
Date: [
|
Date: [
|
||||||
(v) => {
|
(v) => {
|
||||||
const d = v.split('-');
|
const d = v.split('-');
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import { nanoid } from 'nanoid';
|
|||||||
import { ActionDialog, InfoDialog } from 'vj/components/dialog/index';
|
import { ActionDialog, InfoDialog } from 'vj/components/dialog/index';
|
||||||
import Notification from 'vj/components/notification';
|
import Notification from 'vj/components/notification';
|
||||||
import { AutoloadPage } from 'vj/misc/Page';
|
import { AutoloadPage } from 'vj/misc/Page';
|
||||||
import {
|
import { i18n, request, tpl } from 'vj/utils';
|
||||||
i18n, pjax, request, tpl,
|
import uploadFiles from '../upload';
|
||||||
} from 'vj/utils';
|
|
||||||
|
|
||||||
async function startEdit(filename, value, fileCategory = 'file') {
|
async function startEdit(filename, value, fileCategory = 'file') {
|
||||||
const { default: Editor } = await import('vj/components/editor/index');
|
const { default: Editor } = await import('vj/components/editor/index');
|
||||||
@@ -144,17 +143,17 @@ export async function previewFile(ev, type = '') {
|
|||||||
} else Notification.info(i18n('Loading editor...'));
|
} else Notification.info(i18n('Loading editor...'));
|
||||||
const val = await startEdit(filename, content, type || 'file');
|
const val = await startEdit(filename, content, type || 'file');
|
||||||
if (typeof val !== 'string') return null;
|
if (typeof val !== 'string') return null;
|
||||||
Notification.info(i18n('Saving file...'));
|
const file = new File([val], filename, { type: 'text/plain' });
|
||||||
const data = new FormData();
|
const endpoint = new URL(!window.location.href.endsWith('/files')
|
||||||
data.append('filename', filename);
|
? `${window.location.href.substring(0, window.location.href.lastIndexOf('/'))}/files` : '', window.location.href);
|
||||||
data.append('file', new Blob([val], { type: 'text/plain' }));
|
const sidebarType = $(ev.currentTarget).closest('[data-fragment-id]').data('type');
|
||||||
if (type) data.append('type', type);
|
const sidebar = $(ev.currentTarget).closest('[data-fragment-id]').data('sidebar') !== undefined;
|
||||||
data.append('operation', 'upload_file');
|
await uploadFiles(endpoint.toString(), [file], {
|
||||||
const postUrl = !window.location.href.endsWith('/files')
|
type: sidebarType || type,
|
||||||
? `${window.location.href.substring(0, window.location.href.lastIndexOf('/'))}/files` : '';
|
sidebar,
|
||||||
await request.postFile(postUrl, data);
|
pjax: true,
|
||||||
Notification.success(i18n('File saved.'));
|
});
|
||||||
return pjax.request({ push: false });
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataPreviewPage = new AutoloadPage('dataPreview', () => {
|
const dataPreviewPage = new AutoloadPage('dataPreview', () => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ function onBeforeUnload(e) {
|
|||||||
interface UploadOptions {
|
interface UploadOptions {
|
||||||
type?: string;
|
type?: string;
|
||||||
pjax?: boolean;
|
pjax?: boolean;
|
||||||
|
sidebar?: boolean;
|
||||||
singleFileUploadCallback?: (file: File) => any;
|
singleFileUploadCallback?: (file: File) => any;
|
||||||
}
|
}
|
||||||
export default async function uploadFiles(endpoint = '', files: File[] | FileList = [], options: UploadOptions = {}) {
|
export default async function uploadFiles(endpoint = '', files: File[] | FileList = [], options: UploadOptions = {}) {
|
||||||
@@ -65,7 +66,12 @@ export default async function uploadFiles(endpoint = '', files: File[] | FileLis
|
|||||||
}
|
}
|
||||||
window.removeEventListener('beforeunload', onBeforeUnload);
|
window.removeEventListener('beforeunload', onBeforeUnload);
|
||||||
Notification.success(i18n('File uploaded successfully.'));
|
Notification.success(i18n('File uploaded successfully.'));
|
||||||
if (options.pjax) await pjax.request({ push: false });
|
if (options.pjax) {
|
||||||
|
let params = '';
|
||||||
|
if (options.type) params += `?testdata=${options.type === 'testdata'}&additional_file=${options.type === 'additional_file'}`;
|
||||||
|
if (options.sidebar) params += `${params ? '&' : '?'}sidebar=true`;
|
||||||
|
await pjax.request({ push: false, url: `${endpoint}${params || ''}` });
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
Notification.error(i18n('File upload failed: {0}', e.toString()));
|
Notification.error(i18n('File upload failed: {0}', e.toString()));
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ Add module: 添加模块
|
|||||||
Add new data: 添加新数据
|
Add new data: 添加新数据
|
||||||
Add User: 添加用户
|
Add User: 添加用户
|
||||||
Add: 添加
|
Add: 添加
|
||||||
|
additional_file: 附加文件
|
||||||
All {0} Contests: 所有 {0} 比赛
|
All {0} Contests: 所有 {0} 比赛
|
||||||
All Contests: 所有比赛
|
All Contests: 所有比赛
|
||||||
All Homeworks: 所有作业
|
All Homeworks: 所有作业
|
||||||
@@ -529,8 +530,7 @@ New file: 新文件
|
|||||||
New Password: 新密码
|
New Password: 新密码
|
||||||
New Training Plan: 新训练计划
|
New Training Plan: 新训练计划
|
||||||
New: 创建
|
New: 创建
|
||||||
No additional file at current: 当前没有附加文件
|
No {0} at current.: 当前没有{0}。
|
||||||
No additional file at current.: 暂无附加文件。
|
|
||||||
No comments so far...: 目前还没有评论...
|
No comments so far...: 目前还没有评论...
|
||||||
no discussion yet...: 目前没有讨论…
|
no discussion yet...: 目前没有讨论…
|
||||||
No Permission to Attend Contest: 您没有权限参加比赛
|
No Permission to Attend Contest: 您没有权限参加比赛
|
||||||
@@ -814,6 +814,7 @@ Temporary session: 临时会话
|
|||||||
Terms of Service: 服务条款
|
Terms of Service: 服务条款
|
||||||
Test data comes from: 测试数据来自
|
Test data comes from: 测试数据来自
|
||||||
Testdata Config: 测试数据配置
|
Testdata Config: 测试数据配置
|
||||||
|
testdata: 测试数据
|
||||||
Testdata: 测试数据
|
Testdata: 测试数据
|
||||||
Text: 文本
|
Text: 文本
|
||||||
The 'default' role applies to ALL REGISTERED USER.: default 角色作用于<b>所有已注册用户</b>
|
The 'default' role applies to ALL REGISTERED USER.: default 角色作用于<b>所有已注册用户</b>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
.page--problem_config
|
.page--problem_config
|
||||||
.section--problem-sidebar-testdata
|
.problem-sidebar-testdata
|
||||||
.problem-sidebar-testdata__detail
|
max-height: 270px
|
||||||
max-height: 270px
|
overflow-y: auto
|
||||||
overflow-y: auto
|
|
||||||
|
|
||||||
.col--size
|
.col--size
|
||||||
width: 80px
|
width: 80px
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { normalizeSubtasks, readSubtasksFromFiles, size } from '@hydrooj/utils/lib/common';
|
import { normalizeSubtasks, readSubtasksFromFiles } from '@hydrooj/utils/lib/common';
|
||||||
import type { SubtaskType } from 'hydrooj/src/interface';
|
import type { SubtaskType } from 'hydrooj/src/interface';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
@@ -11,7 +11,7 @@ import uploadFiles from 'vj/components/upload';
|
|||||||
import download from 'vj/components/zipDownloader';
|
import download from 'vj/components/zipDownloader';
|
||||||
import { NamedPage } from 'vj/misc/Page';
|
import { NamedPage } from 'vj/misc/Page';
|
||||||
import {
|
import {
|
||||||
i18n, loadReactRedux, request, tpl,
|
i18n, loadReactRedux, pjax, request, tpl,
|
||||||
} from 'vj/utils';
|
} from 'vj/utils';
|
||||||
|
|
||||||
const page = new NamedPage('problem_config', () => {
|
const page = new NamedPage('problem_config', () => {
|
||||||
@@ -25,6 +25,8 @@ const page = new NamedPage('problem_config', () => {
|
|||||||
await new Promise((resolve) => { input.onchange = resolve; });
|
await new Promise((resolve) => { input.onchange = resolve; });
|
||||||
await uploadFiles('./files', input.files, {
|
await uploadFiles('./files', input.files, {
|
||||||
type: 'testdata',
|
type: 'testdata',
|
||||||
|
sidebar: true,
|
||||||
|
pjax: true,
|
||||||
singleFileUploadCallback: (file) => {
|
singleFileUploadCallback: (file) => {
|
||||||
reduxStore.dispatch({
|
reduxStore.dispatch({
|
||||||
type: 'CONFIG_ADD_TESTDATA',
|
type: 'CONFIG_ADD_TESTDATA',
|
||||||
@@ -34,13 +36,6 @@ const page = new NamedPage('problem_config', () => {
|
|||||||
size: file.size,
|
size: file.size,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
$('.testdata-table tbody').append(
|
|
||||||
$(tpl`<tr data-filename="${file.name}" data-size="${file.size.toString()}">
|
|
||||||
<td class="col--name" title="${file.name}"><a href="./file/${file.name}?type=testdata">${file.name}</a></td>
|
|
||||||
<td class="col--size">${size(file.size)}</td>
|
|
||||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
|
||||||
</tr>`),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -62,7 +57,7 @@ const page = new NamedPage('problem_config', () => {
|
|||||||
type: 'CONFIG_DELETE_TESTDATA',
|
type: 'CONFIG_DELETE_TESTDATA',
|
||||||
value: file,
|
value: file,
|
||||||
});
|
});
|
||||||
$(ev.currentTarget).parent().parent().remove();
|
await pjax.request({ url: './files?testdata=false&sidebar=true', push: false });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Notification.error(error.message);
|
Notification.error(error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { size } from '@hydrooj/utils/lib/common';
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { ConfirmDialog } from 'vj/components/dialog';
|
import { ConfirmDialog } from 'vj/components/dialog';
|
||||||
@@ -9,7 +8,7 @@ import uploadFiles from 'vj/components/upload';
|
|||||||
import download from 'vj/components/zipDownloader';
|
import download from 'vj/components/zipDownloader';
|
||||||
import { NamedPage } from 'vj/misc/Page';
|
import { NamedPage } from 'vj/misc/Page';
|
||||||
import {
|
import {
|
||||||
i18n, request, slideDown, slideUp, tpl,
|
i18n, pjax, request, slideDown, slideUp, tpl,
|
||||||
} from 'vj/utils';
|
} from 'vj/utils';
|
||||||
|
|
||||||
const categories = {};
|
const categories = {};
|
||||||
@@ -197,15 +196,8 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
|||||||
await new Promise((resolve) => { input.onchange = resolve; });
|
await new Promise((resolve) => { input.onchange = resolve; });
|
||||||
await uploadFiles('./files', input.files, {
|
await uploadFiles('./files', input.files, {
|
||||||
type: 'additional_file',
|
type: 'additional_file',
|
||||||
singleFileUploadCallback: (file) => {
|
sidebar: true,
|
||||||
$('.additionalfile-table tbody').append(
|
pjax: true,
|
||||||
$(tpl`<tr data-filename="${file.name}" data-size="${file.size.toString()}">
|
|
||||||
<td class="col--name" title="${file.name}"><a href="./file/${file.name}?type=testdata">${file.name}</a></td>
|
|
||||||
<td class="col--size">${size(file.size)}</td>
|
|
||||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
|
||||||
</tr>`),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +214,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
|||||||
type: 'additional_file',
|
type: 'additional_file',
|
||||||
});
|
});
|
||||||
Notification.success(i18n('File have been deleted.'));
|
Notification.success(i18n('File have been deleted.'));
|
||||||
$(ev.currentTarget).parent().parent().remove();
|
await pjax.request({ url: './files?testdata=false&sidebar=true', push: false });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Notification.error(error.message);
|
Notification.error(error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,9 @@
|
|||||||
&.tab--active
|
&.tab--active
|
||||||
border-color: #ed5f82;
|
border-color: #ed5f82;
|
||||||
|
|
||||||
.section--problem-sidebar-additional_file
|
.problem-sidebar-additional_file
|
||||||
.problem-sidebar-additional_file__detail
|
height: 270px
|
||||||
height: 270px
|
overflow-y: auto
|
||||||
overflow-y: auto
|
|
||||||
|
|
||||||
.col--size
|
.col--size
|
||||||
width: 80px
|
width: 80px
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% macro render(text, compact=false) %}
|
{% macro render(text, compact=false, args=[]) %}
|
||||||
<div class="nothing-placeholder{% if compact %} compact{% endif %}">
|
<div class="nothing-placeholder{% if compact %} compact{% endif %}">
|
||||||
<div class="nothing-icon"></div>
|
<div class="nothing-icon"></div>
|
||||||
{{ _(text) }}
|
{{ _(text).format(args) }}
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="section__body typo" data-fragment-id="problem-description">
|
<div class="section__body typo" data-fragment-id="problem-description">
|
||||||
{% if not pdoc.data.length and not pdoc.reference %}
|
{% if not pdoc.data.length and not pdoc.reference %}
|
||||||
<blockquote class="warn">
|
<blockquote class="warn">
|
||||||
<p>{{ _('No testdata at current.') }}</p>
|
<p>{{ _('No {0} at current.').format(_("testdata")) }}</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if typeof(pdoc.config) == 'string' %}
|
{% if typeof(pdoc.config) == 'string' %}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
{% import "components/nothing.html" as nothing with context %}
|
|
||||||
<div class="section__body no-padding problem-files-additional_file" data-fragment-id="problem-files-additional_file">
|
|
||||||
{% if additional_file.length %}
|
|
||||||
<table class="data-table">
|
|
||||||
<colgroup>
|
|
||||||
<col class="col--checkbox">
|
|
||||||
<col class="col--name">
|
|
||||||
<col class="col--size">
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="col--checkbox">
|
|
||||||
<label class="compact checkbox">
|
|
||||||
<input type="checkbox" name="select_all" data-checkbox-toggle="additional_file">
|
|
||||||
</label>
|
|
||||||
</th>
|
|
||||||
<th class="col--name">{{ _('Filename') }}</th>
|
|
||||||
<th class="col--size">{{ _('Size') }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{%- for file in additional_file -%}
|
|
||||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
|
||||||
<td class="col--checkbox">
|
|
||||||
<label class="compact checkbox">
|
|
||||||
<input type="checkbox" data-checkbox-group="additional_file" data-checkbox-range>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td class="col--name" data-preview="additional_file">
|
|
||||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name}) }}">{{ file.name }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="col--size">{{ size(file.size) }}</td>
|
|
||||||
</tr>
|
|
||||||
{%- endfor -%}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
{{ nothing.render('No additional file at current.') }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{% import "components/nothing.html" as nothing with context %}
|
|
||||||
<div class="section__body no-padding problem-files-testdata" data-fragment-id="problem-files-testdata">
|
|
||||||
{% if reference %}
|
|
||||||
<blockquote class="note">
|
|
||||||
<p>{{ _('This is a copy of another problem.') }}</p>
|
|
||||||
</blockquote>
|
|
||||||
{% elif testdata.length %}
|
|
||||||
<table class="data-table">
|
|
||||||
<colgroup>
|
|
||||||
<col class="col--checkbox">
|
|
||||||
<col class="col--name">
|
|
||||||
<col class="col--size">
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="col--checkbox">
|
|
||||||
<label class="compact checkbox">
|
|
||||||
<input type="checkbox" name="select_all" data-checkbox-toggle="testdata">
|
|
||||||
</label>
|
|
||||||
</th>
|
|
||||||
<th class="col--name">{{ _('Filename') }}</th>
|
|
||||||
<th class="col--size">{{ _('Size') }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{%- for file in testdata -%}
|
|
||||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
|
||||||
<td class="col--checkbox">
|
|
||||||
<label class="compact checkbox">
|
|
||||||
<input type="checkbox" data-checkbox-group="testdata" data-checkbox-range>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td class="col--name" data-preview="testdata">
|
|
||||||
{% if handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %}
|
|
||||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:'testdata'} }) }}">{{ file.name }}</a>
|
|
||||||
{% else %}
|
|
||||||
<p>{{ file.name }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td class="col--size">{{ size(file.size) }}</td>
|
|
||||||
</tr>
|
|
||||||
{%- endfor -%}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
{{ nothing.render('No testdata at current.') }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{% import "components/nothing.html" as nothing with context %}
|
||||||
|
{% set _files = testdata if filetype == 'testdata' else additional_file %}
|
||||||
|
<div class="section__body no-padding problem-{{ 'sidebar' if sidebar else 'files' }}-{{ filetype }}" data-fragment-id="problem-files-{{ filetype }}"
|
||||||
|
{% if sidebar %}data-type="{{ filetype }}" data-sidebar{% endif %}>
|
||||||
|
{% if reference %}
|
||||||
|
<blockquote class="note">
|
||||||
|
<p>{{ _('This is a copy of another problem.') }}</p>
|
||||||
|
</blockquote>
|
||||||
|
{% elif _files.length %}
|
||||||
|
<table class="data-table {{ filetype }}-table">
|
||||||
|
<colgroup>
|
||||||
|
{% if not sidebar %}<col class="col--checkbox">{% endif %}
|
||||||
|
<col class="col--name">
|
||||||
|
<col class="col--size">
|
||||||
|
{% if sidebar %}<col class="col--operation">{% endif %}
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{% if not sidebar %}
|
||||||
|
<th class="col--checkbox">
|
||||||
|
<label class="compact checkbox">
|
||||||
|
<input type="checkbox" name="select_all" data-checkbox-toggle="{{ filetype }}">
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
{% endif %}
|
||||||
|
<th class="col--name">{{ _('Filename') }}</th>
|
||||||
|
<th class="col--size">{{ _('Size') }}</th>
|
||||||
|
{% if sidebar %}<th class="col--operation"><span class="icon icon-wrench"></span></th>{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{%- for file in _files -%}
|
||||||
|
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||||
|
{% if not sidebar %}
|
||||||
|
<td class="col--checkbox">
|
||||||
|
<label class="compact checkbox">
|
||||||
|
<input type="checkbox" data-checkbox-group="{{ filetype }}" data-checkbox-range>
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<td class="col--name" data-preview="{{ filetype }}">
|
||||||
|
{% if filetype != 'testdata' or handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %}
|
||||||
|
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:filetype} }) }}">{{ file.name }}</a>
|
||||||
|
{% else %}
|
||||||
|
<p>{{ file.name }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="col--size">{{ size(file.size) }}</td>
|
||||||
|
{% if sidebar %}
|
||||||
|
<td class="col--operation"><a href="javascript:;" name="{{ filetype }}__delete"><span class="icon icon-delete"></span></a></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{%- endfor -%}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
{{ nothing.render('No {0} at current.', compact=sidebar, args=[_(filetype)]) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{% import "components/nothing.html" as nothing with context %}
|
|
||||||
{% import "components/problem.html" as problem with context %}
|
|
||||||
<div class="section side section--problem-sidebar-additional_file">
|
|
||||||
<div class="section__header">
|
|
||||||
<h1 class="section__title">{{ additional_file.length|default(0) }} {{_('Additional File')}}</h1>
|
|
||||||
</div>
|
|
||||||
<ol class="menu">
|
|
||||||
<li class="menu__item flex-row">
|
|
||||||
<a class="menu__link half" href="javascript:;" name="additional_file__upload">
|
|
||||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
|
||||||
</a>
|
|
||||||
<a class="menu__link half" href="javascript:;" name="additional_file__download">
|
|
||||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
<div class="section__body no-padding problem-sidebar-additional_file__detail" data-fragment-id="problem-sidebar-additional_file">
|
|
||||||
{% if additional_file.length %}
|
|
||||||
<table class="data-table additionalfile-table">
|
|
||||||
<colgroup>
|
|
||||||
<col class="col--name">
|
|
||||||
<col class="col--size">
|
|
||||||
<col class="col--operation">
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="col--name">{{ _('Filename') }}</th>
|
|
||||||
<th class="col--size">{{ _('Size') }}</th>
|
|
||||||
<th class="col--operation"><span class="icon icon-wrench"></span></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{%- for file in additional_file -%}
|
|
||||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
|
||||||
<td class="col--name" title="{{ file.name }}" data-preview="additional_file">
|
|
||||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name}) }}">{{ file.name }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="col--size">{{ size(file.size) }}</td>
|
|
||||||
<td class="col--operation"><a href="javascript:;"name="additional_file__delete"><span class="icon icon-delete"></span></a></td>
|
|
||||||
</tr>
|
|
||||||
{%- endfor -%}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
{{ nothing.render('No additional file at current.',compact = true) }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{% import "components/nothing.html" as nothing with context %}
|
|
||||||
{% import "components/problem.html" as problem with context %}
|
|
||||||
<div class="section side section--problem-sidebar-testdata">
|
|
||||||
<div class="section__header">
|
|
||||||
<h1 class="section__title">{{ testdata.length if testdata.length else 0 }} {{_('Testdata')}}</h1>
|
|
||||||
</div>
|
|
||||||
<ol class="menu">
|
|
||||||
<li class="menu__item flex-row">
|
|
||||||
<a class="menu__link half" href="javascript:;" name="testdata__upload">
|
|
||||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
|
||||||
</a>
|
|
||||||
<a class="menu__link half" href="javascript:;" name="testdata__download__all">
|
|
||||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="menu__seperator"></li>
|
|
||||||
</ol>
|
|
||||||
<div class="section__body no-padding problem-sidebar-testdata__detail" data-fragment-id="problem-sidebar-testdata">
|
|
||||||
{% if testdata.length %}
|
|
||||||
<table class="data-table testdata-table">
|
|
||||||
<colgroup>
|
|
||||||
<col class="col--name">
|
|
||||||
<col class="col--size">
|
|
||||||
<col class="col--operation">
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="col--name">{{ _('Filename') }}</th>
|
|
||||||
<th class="col--size">{{ _('Size') }}</th>
|
|
||||||
<th class="col--operation"><span class="icon icon-wrench"></span></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{%- for file in testdata -%}
|
|
||||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
|
||||||
<td class="col--name" title="{{ file.name }}" data-preview="testdata"><a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:'testdata'} }) }}">{{ file.name }}</a></td>
|
|
||||||
<td class="col--size">{{ size(file.size) }}</td>
|
|
||||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
|
||||||
</tr>
|
|
||||||
{%- endfor -%}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
{{ nothing.render('No testdata at current.', compact = true) }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -13,7 +13,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="medium-3 columns">
|
<div class="medium-3 columns">
|
||||||
{% include "partials/problem_sidebar_testdata.html" %}
|
<div class="section side">
|
||||||
|
<div class="section__header">
|
||||||
|
<h1 class="section__title">{{ testdata.length|default(0) }} {{_('Testdata')}}</h1>
|
||||||
|
</div>
|
||||||
|
<ol class="menu">
|
||||||
|
<li class="menu__item flex-row">
|
||||||
|
<a class="menu__link half" href="javascript:;" name="testdata__upload">
|
||||||
|
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||||
|
</a>
|
||||||
|
<a class="menu__link half" href="javascript:;" name="testdata__download__all">
|
||||||
|
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="menu__seperator"></li>
|
||||||
|
</ol>
|
||||||
|
{% set sidebar = true %}
|
||||||
|
{% set filetype = "testdata" %}
|
||||||
|
{% include "partials/problem_files.html" %}
|
||||||
|
</div>
|
||||||
{% set owner_udoc = udoc %}
|
{% set owner_udoc = udoc %}
|
||||||
{% include "partials/problem_sidebar.html" %}
|
{% include "partials/problem_sidebar.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,7 +92,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if page_name == 'problem_edit' %}
|
{% if page_name == 'problem_edit' %}
|
||||||
{% include "partials/problem_sidebar_additional_file.html" %}
|
<div class="section side">
|
||||||
|
<div class="section__header">
|
||||||
|
<h1 class="section__title">{{ additional_file.length|default(0) }} {{_('Additional File')}}</h1>
|
||||||
|
</div>
|
||||||
|
<ol class="menu">
|
||||||
|
<li class="menu__item flex-row">
|
||||||
|
<a class="menu__link half" href="javascript:;" name="additional_file__upload">
|
||||||
|
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||||
|
</a>
|
||||||
|
<a class="menu__link half" href="javascript:;" name="additional_file__download">
|
||||||
|
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
{% set sidebar = true %}
|
||||||
|
{% set filetype = "additional_file" %}
|
||||||
|
{% include "partials/problem_files.html" %}
|
||||||
|
</div>
|
||||||
{% set owner_udoc = udoc %}
|
{% set owner_udoc = udoc %}
|
||||||
{% include "partials/problem_sidebar.html" %}
|
{% include "partials/problem_sidebar.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ noscript_note.render() }}
|
{{ noscript_note.render() }}
|
||||||
{% include "partials/problem_files-testdata.html" %}
|
{% set filetype = "testdata" %}
|
||||||
|
{% include "partials/problem_files.html" %}
|
||||||
{% if not reference and (handler.user.own(pdoc) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) %}
|
{% if not reference and (handler.user.own(pdoc) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) %}
|
||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<button class="rounded button" name="download_selected_testdata">{{ _('Download Selected') }}</button>
|
<button class="rounded button" name="download_selected_testdata">{{ _('Download Selected') }}</button>
|
||||||
@@ -36,7 +37,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include "partials/problem_files-additional_file.html" %}
|
{% set filetype = "additional_file" %}
|
||||||
|
{% include "partials/problem_files.html" %}
|
||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<button class="rounded button" name="download_selected_file">{{ _('Download Selected') }}</button>
|
<button class="rounded button" name="download_selected_file">{{ _('Download Selected') }}</button>
|
||||||
{% if handler.user.own(pdoc, perm.PERM_EDIT_PROBLEM_SELF) or handler.user.hasPerm(perm.PERM_EDIT_PROBLEM) %}
|
{% if handler.user.own(pdoc, perm.PERM_EDIT_PROBLEM_SELF) or handler.user.hasPerm(perm.PERM_EDIT_PROBLEM) %}
|
||||||
|
|||||||
Reference in new issue
Block a user