ui: scoreboard: virtual-scroll

This commit is contained in:
undefined committed 2023-04-28 11:10:59 +08:00
1 parent 82460cf8e9
commit d1c996dfab
2 files changed
+77 -49

No files matched your search

@@ -1,3 +1,4 @@
import Clusterize from 'clusterize.js';
import $ from 'jquery';
import { NamedPage } from 'vj/misc/Page';
import { pjax } from 'vj/utils';
@@ -5,7 +6,7 @@ import { pjax } from 'vj/utils';
const page = new NamedPage('contest_scoreboard', () => {
const { tdoc } = UiContext;
const key = `scoreboard-star/${tdoc.domainId}/${tdoc.docId}`;
const read = () => JSON.parse(localStorage.getItem(key) || '[]');
const read = () => JSON.parse(localStorage.getItem(key) || '[]').map((i) => +i);
const write = (data) => localStorage.setItem(key, JSON.stringify(data));
read().forEach((uid) => $(`.star.user--${uid}`).addClass('activated'));
@@ -23,22 +24,40 @@ const page = new NamedPage('contest_scoreboard', () => {
write(star);
});
const rows: Record<number, string> = {};
const total = [];
let nowRendering = [];
const unrank = [];
for (const line of $('.data-table tbody tr')) {
const uid = +$(line).find('[data-uid]').data('uid');
line.style.display = 'table-row';
rows[uid] = line.outerHTML;
nowRendering.push(uid);
total.push(uid);
if ($(line).find('.rank--unrank').length) unrank.push(uid);
$(line).remove();
}
const virtualizedList = new Clusterize({
rows: nowRendering.map((i) => rows[i]),
scrollElem: $('.data-table').get(0),
contentElem: $('tbody').get(0),
});
$('.select.filter').on('change', (e) => {
const val = $(e.target).val();
if (val === 'all') {
$('.data-table tbody tr').show();
} else if (val === 'star') {
$('.data-table tbody tr').hide();
read().forEach((uid) => $(`.star.user--${uid}`).closest('tr').show());
} else if (val === 'rank') {
$('.data-table tbody tr').show();
$('.rank--unrank').closest('tr').hide();
} else {
$('.data-table tbody tr').hide();
if (val === 'all') nowRendering = total;
else if (val === 'star') nowRendering = read();
else if (val === 'rank') nowRendering = total.filter((i) => !unrank.includes(i));
else {
nowRendering = [];
const uids = val.toString().split(',').map((i) => +i.trim()).filter((i) => i);
if (!uids?.length) return;
uids.forEach((uid) => $(`.user--${uid}`).closest('tr').show());
for (const uid of total) {
if (!uids.includes(+uid)) continue;
nowRendering.push(uid);
}
}
virtualizedList.update(nowRendering.map((i) => rows[i]));
});
const beginAt = new Date(UiContext.tdoc.beginAt).getTime();
@@ -6,6 +6,41 @@
</a>
{% endmacro %}
{% macro scoreboardRow(row) %}
{%- for column in row -%}
<td class="col--{{ rows[0][loop.index0]['type'] }}"{% if column.style %} style="{{ column.style }}"{% endif %}>
{%- if column.type == 'rank' -%}
<span class="{{ 'rank--unrank' if column.value == '0' else 'rank--normal' }}">{{ '*' if column.value == '0' else column.value|string|nl2br|safe }}</span>
{%- elif column.type == 'user' -%}
{%- set canView = canViewAll or handler.user._id == column.raw -%}
<button class="star user--{{ column.raw }}" data-uid="{{ column.raw }}">
<span class="starred--hide"><span class="icon icon-star--outline" data-tooltip="{{ _('Star') }}"></span></span>
<span class="starred--show"><span class="icon icon-star" data-tooltip="{{ _('Unstar') }}"></span></span>
</button>
{{ user.render_inline(udict[column.raw], badge=false) }}
{%- elif column.type == 'record' and column.raw -%}
<a href="{{ url('record_detail', rid=column.raw) if canView else '' }}"{% if column.hover %} data-tooltip="{{ column.hover }}"{% endif %}>
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(column.score|default(column.value)) }}">{{ column.value|string|nl2br|safe }}</span>
</a>
{%- elif column.type == 'records' -%}
{%- for record in column.raw -%}
{%- if loop.index0 -%}/{%- endif -%}
{%- if record.raw -%}
<a href="{{ url('record_detail', rid=record.raw) if canView else '' }}">
{%- set _color = utils.status.getScoreColor(record.score|default(record.value)) -%}
<span style="font-weight:bold;color:{{ _color }}">{{ record.value|string|nl2br|safe }}</span>
</a>
{%- else -%}
{{ record.value|string|nl2br|safe }}
{%- endif -%}
{%- endfor -%}
{%- else -%}
<span{% if column.hover %} data-tooltip="{{ column.hover }}"{% endif %}>{{ column.value|string|nl2br|safe }}</span>
{%- endif -%}
</td>
{%- endfor -%}
{% endmacro %}
<div data-fragment-id="scoreboard">
{% if model.contest.isLocked(tdoc) %}
<div class="section__body no-padding">
@@ -42,42 +77,16 @@
</thead>
<tbody>
{%- set canViewAll = handler.user.own(tdoc) or model.contest.canShowRecord.call(handler, tdoc) -%}
{%- for row in rows -%}{%- if loop.index0 > 0 -%}
<tr>
{%- for column in row -%}
<td class="col--{{ rows[0][loop.index0]['type'] }}"{% if column.style %} style="{{ column.style }}"{% endif %}>
{%- if column.type == 'rank' -%}
<span class="{{ 'rank--unrank' if column.value == '0' else 'rank--normal' }}">{{ '*' if column.value == '0' else column.value|string|nl2br|safe }}</span>
{%- elif column.type == 'user' -%}
{%- set canView = canViewAll or handler.user._id == column.raw -%}
<button class="star user--{{ column.raw }}" data-uid="{{ column.raw }}">
<span class="starred--hide"><span class="icon icon-star--outline" data-tooltip="{{ _('Star') }}"></span></span>
<span class="starred--show"><span class="icon icon-star" data-tooltip="{{ _('Unstar') }}"></span></span>
</button>
{{ user.render_inline(udict[column.raw], badge=false) }}
{%- elif column.type == 'record' and column.raw -%}
<a href="{{ url('record_detail', rid=column.raw) if canView else '' }}" data-tooltip="{{ column.hover }}">
<span style="font-weight:bold;color:{{ utils.status.getScoreColor(column.score|default(column.value)) }}">{{ column.value|string|nl2br|safe }}</span>
</a>
{%- elif column.type == 'records' -%}
{%- for record in column.raw -%}
{%- if loop.index0 -%}/{%- endif -%}
{%- if record.raw -%}
<a href="{{ url('record_detail', rid=record.raw) if canView else '' }}">
{%- set _color = utils.status.getScoreColor(record.score|default(record.value)) -%}
<span style="font-weight:bold;color:{{ _color }}">{{ record.value|string|nl2br|safe }}</span>
</a>
{%- else -%}
{{ record.value|string|nl2br|safe }}
{%- endif -%}
{%- endfor -%}
{%- else -%}
<span data-tooltip="{{ column.hover }}">{{ column.value|string|nl2br|safe }}</span>
{%- endif -%}
</td>
{%- endfor -%}
</tr>
{%- endif -%}{%- endfor -%}
{%- for row in rows -%}
{%- if loop.index0 == 1001 -%}
{{ noscript_note.render() }}
{%- endif -%}
{%- if loop.index0 > 1000 -%}
<tr style="display:none">{{ scoreboardRow(row) }}</tr>
{%- elif loop.index0 > 0 -%}
<tr>{{ scoreboardRow(row) }}</tr>
{%- endif -%}
{%- endfor -%}
</tbody>
</table>
</div>