511 lines
15 KiB
JavaScript
511 lines
15 KiB
JavaScript
const SEARCH_DELAY = 100;
|
|
let searchTimer = undefined;
|
|
let resultTemplate;
|
|
let searchResult;
|
|
let searchHighlight;
|
|
let manualRating = false;
|
|
let manualRank = false;
|
|
|
|
function initSearch() {
|
|
let needle = $('#needle')[0].value.trim();
|
|
if (searchTimer) {
|
|
clearTimeout(searchTimer);
|
|
}
|
|
searchTimer = setTimeout(() => {
|
|
search(needle);
|
|
}, SEARCH_DELAY);
|
|
}
|
|
|
|
function searchResultShown() {
|
|
return !(!searchResult || searchResult.length === 0)
|
|
}
|
|
|
|
function search(needle) {
|
|
needle = needle.trim();
|
|
if (needle && (needle === '*' || needle.length > 2)) {
|
|
let form = $('#search-form')[0];
|
|
let search = {
|
|
needle: needle,
|
|
// aga: form.val('aga'),
|
|
egf: form.val('egf'),
|
|
ffg: form.val('ffg'),
|
|
}
|
|
let country = form.val('countryFilter');
|
|
if (country) search.countryFilter = country;
|
|
let searchFormState = {
|
|
countryFilter: !!country,
|
|
// aga: search.aga,
|
|
egf: search.egf,
|
|
ffg: search.ffg
|
|
};
|
|
store('searchFormState', searchFormState);
|
|
api.postJson('search', search)
|
|
.then(result => {
|
|
if (Array.isArray(result)) {
|
|
searchResult = result
|
|
let html = resultTemplate.render(result);
|
|
$('#search-result')[0].innerHTML = html;
|
|
if (needle === '*') {
|
|
setTimeout(() => {
|
|
let scrollTo = $('#needle')[0].value.trim();
|
|
while (scrollTo.length > 0) {
|
|
let target = $(`#search-result .result-line[data-name^="${scrollTo}"i]`);
|
|
if (target.length > 0) {
|
|
target[0].scrollIntoView({ behavior: "smooth", block: "center" });
|
|
break;
|
|
}
|
|
scrollTo = scrollTo.substring(0, scrollTo.length - 1);
|
|
}
|
|
}, 0);
|
|
} else {
|
|
let scrollable = $('#player .popup-body');
|
|
scrollable[0].scrollTop = 0;
|
|
}
|
|
} else console.log(result);
|
|
});
|
|
} else {
|
|
$('#search-result').clear();
|
|
searchTimer = undefined;
|
|
searchResult = undefined;
|
|
searchHighlight = undefined;
|
|
}
|
|
}
|
|
|
|
function parseRank(rank) {
|
|
let groups = /(\d+)([kd])/.exec(rank)
|
|
if (groups) {
|
|
let level = parseInt(groups[1]);
|
|
let letter = groups[2];
|
|
switch (letter) {
|
|
case 'k': return -level;
|
|
case 'd': return level - 1;
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function fillPlayer(player) {
|
|
// hack UK / GB
|
|
let country = player.country.toLowerCase();
|
|
if ('uk' === country) country = 'gb';
|
|
let form = $('#player-form')[0];
|
|
form.val('name', player.name);
|
|
form.val('firstname', player.firstname);
|
|
form.val('country', country);
|
|
form.val('club', player.club);
|
|
form.val('rank', parseRank(player.rank));
|
|
form.val('rating', player.rating);
|
|
form.val('final', false);
|
|
form.val('ffg_id', player.ffg);
|
|
form.val('egf_id', player.egf);
|
|
$('#needle')[0].value = '';
|
|
initSearch();
|
|
$('#register').focus();
|
|
}
|
|
|
|
function addPlayers() {
|
|
let form = $('#player-form')[0];
|
|
// keep preliminary/final status
|
|
let status = form.val('final') || false;
|
|
form.reset();
|
|
// initial search checkboxes position
|
|
['countryFilter', /* 'aga', */ 'egf', 'ffg'].forEach(id => {
|
|
let value = store(id);
|
|
let ctl = $(`#${id}`);
|
|
if (value !== null && typeof(value) !== 'undefined' && ctl.length !== 0) {
|
|
ctl[0].checked = value;
|
|
}
|
|
});
|
|
form.val('final', status);
|
|
$('#player').removeClass('edit').addClass('create');
|
|
modal('player');
|
|
$('#needle').focus();
|
|
store('addingPlayers', true);
|
|
}
|
|
|
|
function bulkUpdate(players) {
|
|
Promise.all(players.map(p => api.putJson(`tour/${tour_id}/part/${p.id}`, p)))
|
|
.then((values) => window.location.reload());
|
|
}
|
|
|
|
let tableSort;
|
|
|
|
onLoad(() => {
|
|
$('input.numeric').imask({
|
|
mask: Number,
|
|
scale: 0,
|
|
min: 0,
|
|
max: 4000
|
|
});
|
|
|
|
let prevSort = store('registrationSort');
|
|
if (prevSort) {
|
|
let columns = $('#players thead th');
|
|
columns.forEach(th => {
|
|
th.removeAttribute('data-sort-default');
|
|
th.removeAttribute('aria-sort');
|
|
})
|
|
prevSort.forEach(i => {
|
|
let col = columns[Math.abs(i)];
|
|
col.setAttribute('data-sort-default', '1');
|
|
if (i < 0) {
|
|
// take into account TableSort initiailization bug
|
|
col.setAttribute('aria-sort', 'ascending');
|
|
}
|
|
});
|
|
}
|
|
tableSort = new Tablesort($('#players')[0]);
|
|
$('#players').on('afterSort', e => {
|
|
let sort = [];
|
|
$('#players thead th').forEach((th, i) => {
|
|
let attr = th.attr('aria-sort');
|
|
if (attr) {
|
|
let dir = i;
|
|
if (attr === 'descending') dir = -dir;
|
|
sort.push(dir);
|
|
}
|
|
});
|
|
store('registrationSort', sort);
|
|
});
|
|
|
|
$('#add').on('click', e => {
|
|
addPlayers();
|
|
});
|
|
$('#cancel-register').on('click', e => {
|
|
e.preventDefault();
|
|
close_modal();
|
|
searchHighlight = undefined;
|
|
return false;
|
|
});
|
|
|
|
$('#register').on('click', e => {
|
|
let form = e.target.closest('form');
|
|
let valid = true;
|
|
let required = ['name', 'firstname', 'country', 'club', 'rank', 'rating'];
|
|
for (let name of required) {
|
|
let ctl = form.find(`[name=${name}]`)[0];
|
|
let val = ctl.value;
|
|
if (val) {
|
|
ctl.setCustomValidity('');
|
|
} else {
|
|
valid = false;
|
|
ctl.setCustomValidity(msg('required_field'));
|
|
}
|
|
}
|
|
if (!valid) {
|
|
$('#player :invalid').forEach(elem => elem.reportValidity());
|
|
return;
|
|
}
|
|
// $('#player-form')[0].requestSubmit() not working?!
|
|
$('#player-form')[0].dispatchEvent(new CustomEvent('submit', {cancelable: true}));
|
|
});
|
|
$('#search-form').on('submit', e => {
|
|
// this form is never meant to be submitted
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
$('#player-form').on('submit', e => {
|
|
e.preventDefault();
|
|
if ($('#register').hasClass('disabled')) {
|
|
// user pressed enter
|
|
return false;
|
|
}
|
|
let form = $('#player-form')[0];
|
|
let player = {
|
|
name: form.val('name'),
|
|
firstname: form.val('firstname'),
|
|
rating: form.val('rating'),
|
|
rank: form.val('rank'),
|
|
country: form.val('country'),
|
|
club: form.val('club'),
|
|
skip: form.find('input.participation').map((input,i) => [i+1, input.checked]).filter(arr => !arr[1]).map(arr => arr[0]),
|
|
final: form.val('final')
|
|
}
|
|
for (let origin of ['egf', 'ffg']) {
|
|
let value = form.val(`${origin}_id`);
|
|
if (value) {
|
|
player[origin] = value;
|
|
}
|
|
}
|
|
if ($('#player').hasClass('create')) {
|
|
api.postJson(`tour/${tour_id}/part`, player)
|
|
.then(player => {
|
|
if (player !== 'error') {
|
|
store('registrationSuccess', true);
|
|
store('scrollIntoView', player.id)
|
|
window.location.reload();
|
|
}
|
|
});
|
|
} else {
|
|
let id = form.val('id');
|
|
player['id'] = id;
|
|
api.putJson(`tour/${tour_id}/part/${id}`, player)
|
|
.then(player => {
|
|
if (player !== 'error') {
|
|
store('registrationSuccess', true);
|
|
store('scrollIntoView', id)
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
$('#players > tbody > tr').on('click', e => {
|
|
let regStatus = e.target.closest('td.reg-status, td.participating');
|
|
if (regStatus) return;
|
|
let id = e.target.closest('tr').attr('data-id');
|
|
api.getJson(`tour/${tour_id}/part/${id}`)
|
|
.then(player => {
|
|
if (player !== 'error') {
|
|
let form = $('#player-form')[0];
|
|
form.val('id', player.id);
|
|
form.val('name', player.name);
|
|
form.val('firstname', player.firstname);
|
|
form.val('rating', player.rating);
|
|
form.val('rank', player.rank);
|
|
form.val('country', player.country.toLowerCase());
|
|
form.val('club', player.club);
|
|
form.val('final', player.final);
|
|
if (player.final) $('#final-reg').addClass('final');
|
|
else $('#final-reg').removeClass('final');
|
|
for (r = 1; r <= tour_rounds; ++r) {
|
|
form.val(`r${r}`, !(player.skip && player.skip.includes(r)));
|
|
}
|
|
$('#player').removeClass('create').addClass('edit');
|
|
$('#register').addClass('disabled');
|
|
modal('player');
|
|
}
|
|
});
|
|
});
|
|
resultTemplate = jsrender.templates($('#result')[0]);
|
|
$('#needle').on('input', e => {
|
|
initSearch();
|
|
});
|
|
$('#clear-search').on('click', e => {
|
|
$('#needle')[0].value = '';
|
|
$('#search-result').clear();
|
|
});
|
|
let searchFormState = store('searchFormState')
|
|
if (searchFormState) {
|
|
for (let id of ["countryFilter", /* "aga", */ "egf", "ffg"]) {
|
|
let ctl = $(`#${id}`);
|
|
if (ctl.length !== 0) {
|
|
ctl[0].checked = searchFormState[id];
|
|
}
|
|
}
|
|
}
|
|
$('#search-form .toggle').on('click', e => {
|
|
let chk = e.target.closest('.toggle');
|
|
let checkbox = chk.find('input')[0];
|
|
checkbox.checked = !checkbox.checked;
|
|
let id = checkbox.getAttribute('id');
|
|
let value = checkbox.checked;
|
|
store(id, value);
|
|
initSearch();
|
|
});
|
|
$('#reglist-mode').on('change', e => {
|
|
let mode = e.target.value;
|
|
$('td.reg-status').forEach(node => node.parentNode.removeClass('filtered'));
|
|
if (mode === 'prelim') {
|
|
$('td.reg-status.final').forEach(node => node.parentNode.addClass('filtered'));
|
|
} else if (mode === 'final') {
|
|
$('td.reg-status:not(.final)').forEach(node => node.parentNode.addClass('filtered'));
|
|
}
|
|
});
|
|
document.on('click', e => {
|
|
let resultLine = e.target.closest('.result-line');
|
|
if (resultLine) {
|
|
let index = e.target.closest('.result-line').data('index');
|
|
fillPlayer(searchResult[index]);
|
|
}
|
|
let tab = document.location.hash;
|
|
if (store('addingPlayers') && tab === '#registration') {
|
|
let modal = e.target.closest('#player');
|
|
if (!modal) {
|
|
let button = e.target.closest('button');
|
|
if (!button) {
|
|
if (searchResultShown()) {
|
|
$('#needle')[0].value = '';
|
|
initSearch();
|
|
} else {
|
|
close_modal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
$('#unregister').on('click', e => {
|
|
let form = $('#player-form')[0];
|
|
let id = form.val('id');
|
|
let confirmMessage = $('#unregister-player').text();
|
|
if (confirm(confirmMessage)) {
|
|
api.deleteJson(`tour/${tour_id}/part/${id}`)
|
|
.then(ret => {
|
|
if (ret !== 'error') {
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
$('#reg-status').on('click', e => {
|
|
let current = $('#final-reg').hasClass('final');
|
|
if (current) {
|
|
$('input[name="final"]')[0].value = false;
|
|
$('#final-reg').removeClass('final');
|
|
} else {
|
|
$('input[name="final"]')[0].value = true;
|
|
$('#final-reg').addClass('final');
|
|
}
|
|
});
|
|
$('.reg-status').on('click', e => {
|
|
let cell = e.target.closest('td');
|
|
let tr = e.target.closest('tr');
|
|
let id = tr.data('id');
|
|
let newStatus = !cell.hasClass('final');
|
|
api.putJson(`tour/${tour_id}/part/${id}`, {
|
|
id: id,
|
|
final: newStatus
|
|
}).then(player => {
|
|
if (player !== 'error') {
|
|
tr.toggleClass('final');
|
|
cell.toggleClass('final');
|
|
standingsUpToDate = false;
|
|
pairablesUpToDate = false;
|
|
}
|
|
});
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
$('#filter').on('input', (e) => {
|
|
let input = e.target;
|
|
let value = input.value.toUpperCase();
|
|
if (value === '') $('tbody > tr').removeClass('hidden');
|
|
else $('tbody > tr').forEach(tr => {
|
|
let txt = tr.data('text');
|
|
if (txt && txt.indexOf(value) === -1) tr.addClass('hidden');
|
|
else tr.removeClass('hidden');
|
|
});
|
|
});
|
|
manualRating = ($('#rating')[0].value !== '');
|
|
manualRank = ($('#rank')[0].value !== '');
|
|
$('#player input[name="rating"]').on('input', e=>{
|
|
manualRating = true;
|
|
});
|
|
$('#player select[name="rank"]').on('input', e=>{
|
|
let rank = e.target.value;
|
|
let ratingCtl = $('#player input[name="rating"]')[0];
|
|
if (!$('#rating')[0].value || !manualRating) {
|
|
ratingCtl.value = 2050 + 100 * rank;
|
|
}
|
|
});
|
|
$('#filter-box i').on('click', e => {
|
|
$('#filter')[0].value = '';
|
|
$('tbody > tr').removeClass('hidden');
|
|
});
|
|
$('#edit-macmahon-groups').on('click', e => {
|
|
modal('macmahon-groups');
|
|
store('macmahonGroups', true);
|
|
});
|
|
if (store('addingPlayers')) {
|
|
addPlayers();
|
|
if (store('registrationSuccess')) {
|
|
$('#player').addClass('successful');
|
|
setTimeout(() => $('#player .success-feedback').addClass('done'), 0);
|
|
}
|
|
}
|
|
store.remove('registrationSuccess');
|
|
let scrollIntoView = store('scrollIntoView');
|
|
if (scrollIntoView) {
|
|
let row = $(`tr[data-id="${scrollIntoView}"`);
|
|
if (row.length !== 0) {
|
|
row.addClass('highlighted');
|
|
store.remove('scroll');
|
|
setTimeout(()=>{
|
|
row[0].scrollIntoView({ behavior: "smooth", block: "center" });
|
|
}, 100);
|
|
}
|
|
}
|
|
store.remove('scrollIntoView');
|
|
if (store('macmahonGroups')) {
|
|
modal('macmahon-groups');
|
|
}
|
|
// mac mahon groups...
|
|
$('#under-to-top').on('click', e => {
|
|
let players = $('#under-group .selected').map(item => (
|
|
{
|
|
id: parseInt(item.data("id")),
|
|
mmsCorrection: parseInt(item.data("correction")) + 1
|
|
}));
|
|
bulkUpdate(players);
|
|
});
|
|
$('#top-to-under').on('click', e => {
|
|
let players = $('#top-group .selected').map(item => (
|
|
{
|
|
id: parseInt(item.data("id")),
|
|
mmsCorrection: parseInt(item.data("correction")) - 1
|
|
}));
|
|
bulkUpdate(players);
|
|
});
|
|
$('#top-to-super').on('click', e => {
|
|
let players = $('#top-group .selected').map(item => (
|
|
{
|
|
id: parseInt(item.data("id")),
|
|
mmsCorrection: parseInt(item.data("correction")) + 1
|
|
}));
|
|
bulkUpdate(players);
|
|
});
|
|
$('#super-to-top').on('click', e => {
|
|
let players = $('#super-group .selected').map(item => (
|
|
{
|
|
id: parseInt(item.data("id")),
|
|
mmsCorrection: parseInt(item.data("correction")) - 1
|
|
}));
|
|
bulkUpdate(players);
|
|
});
|
|
$('#reset-macmahon-groups').on('click', e => {
|
|
let players = $('#macmahon-groups .listitem').map(item => (
|
|
{
|
|
id: parseInt(item.data("id")),
|
|
mmsCorrection: 0
|
|
}));
|
|
bulkUpdate(players);
|
|
});
|
|
$('#browse-players').on('click', e => {
|
|
search('*');
|
|
});
|
|
$('.player-fields').on('change input', e => {
|
|
$('#register').removeClass('disabled');
|
|
});
|
|
$('.participation label').on('click', e => {
|
|
let part = e.target;
|
|
let id = part.closest('tr').data('id');
|
|
let round = parseInt(part.text());
|
|
let skip = new Set(part.closest('.participation').find('label.red').map(it => parseInt(it.innerText)));
|
|
if (skip.has(round)) skip.delete(round);
|
|
else skip.add(round);
|
|
api.putJson(`tour/${tour_id}/part/${id}`, {
|
|
id: id,
|
|
skip: Array.from(skip)
|
|
}).then(player => {
|
|
if (player !== 'error') {
|
|
part.toggleClass('red');
|
|
part.toggleClass('green');
|
|
standingsUpToDate = false;
|
|
pairablesUpToDate = false;
|
|
}
|
|
});
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
$('#rating').on('input', e => {
|
|
if (!$('#rank')[0].value || !manualRank) {
|
|
let rank = (e.target.value - 2050) / 100;
|
|
console.log(rank);
|
|
$('#rank')[0].value = `${rank}`;
|
|
}
|
|
return true;
|
|
});
|
|
$('#rank').on('input', e => {
|
|
manualRank = true;
|
|
});
|
|
});
|