feat(exam-correct): validate user input stub
This commit is contained in:
parent
36e90102c4
commit
431d004665
@ -9,13 +9,20 @@ import moment from 'moment';
|
||||
|
||||
|
||||
const EXAM_CORRECT_URL_POST = 'correct';
|
||||
const EXAM_CORRECT_HEADERS = {
|
||||
'X-XSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
|
||||
'Content-Type': HttpClient.ACCEPT.JSON,
|
||||
'Accept': HttpClient.ACCEPT.JSON,
|
||||
};
|
||||
|
||||
|
||||
const EXAM_CORRECT_IDENT = 'uw-exam-correct';
|
||||
const EXAM_CORRECT_PART_INPUT_ATTR = 'uw-exam-correct--part-input';
|
||||
const EXAM_CORRECT_SEND_BTN_ID = 'exam-correct__send-btn';
|
||||
const EXAM_CORRECT_PARTICIPANT_INPUT_ID = 'exam-correct__participant';
|
||||
const EXAM_CORRECT_PARTICIPANT_INPUT_ID = 'exam-correct__user';
|
||||
const EXAM_CORRECT_USER_INPUT_CANDIDATES_ID = 'exam-correct__user-candidates';
|
||||
const EXAM_CORRECT_INPUT_BODY_ID = 'exam-correct__new';
|
||||
const EXAM_CORRECT_PARTICIPANT_ATTR = 'exam-correct--participant';
|
||||
const EXAM_CORRECT_PARTICIPANT_ATTR = 'exam-correct--user';
|
||||
|
||||
const INPUT_EMPTY_CLASS = 'input--invalid';
|
||||
|
||||
@ -33,7 +40,8 @@ export class ExamCorrect {
|
||||
_element;
|
||||
|
||||
_sendBtn;
|
||||
_participantInput;
|
||||
_userInput;
|
||||
_userInputCandidates;
|
||||
_partInputs;
|
||||
|
||||
constructor(element, app) {
|
||||
@ -48,40 +56,65 @@ export class ExamCorrect {
|
||||
this._element = element;
|
||||
this._app = app;
|
||||
this._sendBtn = document.getElementById(EXAM_CORRECT_SEND_BTN_ID);
|
||||
this._participantInput = document.getElementById(EXAM_CORRECT_PARTICIPANT_INPUT_ID);
|
||||
this._userInput = document.getElementById(EXAM_CORRECT_PARTICIPANT_INPUT_ID);
|
||||
this._userInputCandidates = document.getElementById(EXAM_CORRECT_USER_INPUT_CANDIDATES_ID);
|
||||
this._partInputs = [...this._element.querySelectorAll(`input[${EXAM_CORRECT_PART_INPUT_ATTR}]`)];
|
||||
|
||||
if (this._sendBtn)
|
||||
this._sendBtn.addEventListener('click', this._sendCorrectionHandler.bind(this));
|
||||
else console.error('ExamCorrect utility could not detect send button!');
|
||||
|
||||
if (this._participantInput)
|
||||
this._participantInput.addEventListener('focusout', this._validateParticipantInput.bind(this));
|
||||
else throw new Error('ExamCorrect utility could not detect participant input!');
|
||||
if (this._userInput)
|
||||
this._userInput.addEventListener('focusout', this._validateUserInput.bind(this));
|
||||
else throw new Error('ExamCorrect utility could not detect user input!');
|
||||
|
||||
if (!this._userInputCandidates) {
|
||||
throw new Error('ExamCorrect utility could not detect user input candidate list!');
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._sendBtn.removeEventListener('click', this._sendCorrectionHandler);
|
||||
this._participantInput.removeEventListener('change', this._validateParticipantInput);
|
||||
this._participantInput.removeEventListener('input', this._removeInputEmptyClassHandler);
|
||||
this._userInput.removeEventListener('change', this._validateUserInput);
|
||||
this._userInput.removeEventListener('input', this._removeInputEmptyClassHandler);
|
||||
}
|
||||
|
||||
_validateParticipantInput(event) {
|
||||
console.log('WIP _validateParticipantInput', event);
|
||||
_validateUserInput() {
|
||||
const user = this._userInput.value;
|
||||
|
||||
if (!user) return;
|
||||
|
||||
const body = {
|
||||
name: user,
|
||||
results: {},
|
||||
op: false,
|
||||
};
|
||||
|
||||
this._app.httpClient.post({
|
||||
url: EXAM_CORRECT_URL_POST,
|
||||
headers: EXAM_CORRECT_HEADERS,
|
||||
body: JSON.stringify(body),
|
||||
}).then(
|
||||
(response) => response.json()
|
||||
).then(
|
||||
(response) => this._processResponse(response, user)
|
||||
).catch((error) => {
|
||||
console.error('Error while validating user input', error);
|
||||
});
|
||||
}
|
||||
|
||||
_sendCorrectionHandler(event) {
|
||||
console.log('WIP _sendCorrectionHandler', event);
|
||||
|
||||
// refocus participant input element for convenience
|
||||
this._participantInput.focus();
|
||||
// refocus user input element for convenience
|
||||
this._userInput.focus();
|
||||
|
||||
const participant = this._participantInput.value;
|
||||
const user = this._userInput.value;
|
||||
|
||||
// abort send if the participant input is empty
|
||||
if (!participant) {
|
||||
this._participantInput.classList.add(INPUT_EMPTY_CLASS);
|
||||
this._participantInput.addEventListener('input', this._removeInputEmptyClassHandler.bind(this), { once: true });
|
||||
// abort send if the user input is empty
|
||||
if (!user) {
|
||||
this._userInput.classList.add(INPUT_EMPTY_CLASS);
|
||||
this._userInput.addEventListener('input', this._removeInputEmptyClassHandler.bind(this), { once: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -106,9 +139,9 @@ export class ExamCorrect {
|
||||
const now = moment();
|
||||
dateTD.appendChild(document.createTextNode(now.format(MOMENT_FORMAT)));
|
||||
dateTD.setAttribute('date', moment());
|
||||
const participantTD = document.createElement('TD');
|
||||
participantTD.appendChild(document.createTextNode(participant));
|
||||
participantTD.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, participant);
|
||||
const userTD = document.createElement('TD');
|
||||
userTD.appendChild(document.createTextNode(user));
|
||||
userTD.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, user);
|
||||
const partTDs = this._partInputs.map((input) => {
|
||||
const partTD = document.createElement('TD');
|
||||
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
|
||||
@ -120,7 +153,7 @@ export class ExamCorrect {
|
||||
const statusDiv = document.createElement('DIV');
|
||||
statusDiv.classList.add('exam-correct--loading');
|
||||
statusTD.appendChild(statusDiv);
|
||||
[dateTD,participantTD,...partTDs, statusTD].forEach((td) => {
|
||||
[dateTD,userTD,...partTDs, statusTD].forEach((td) => {
|
||||
td.classList.add('table__td');
|
||||
correctionRow.appendChild(td);
|
||||
});
|
||||
@ -129,41 +162,65 @@ export class ExamCorrect {
|
||||
|
||||
// clear input values on validation success
|
||||
// TODO only clear input on post success
|
||||
[this._participantInput, ...this._partInputs].forEach(clearInput);
|
||||
[this._userInput, ...this._partInputs].forEach(clearInput);
|
||||
|
||||
const url = EXAM_CORRECT_URL_POST;
|
||||
const headers = {
|
||||
'X-XSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
|
||||
'Content-Type': HttpClient.ACCEPT.JSON,
|
||||
'Accept': HttpClient.ACCEPT.JSON,
|
||||
};
|
||||
const body = {
|
||||
name: participant,
|
||||
name: user,
|
||||
results: results,
|
||||
op: true,
|
||||
};
|
||||
|
||||
this._app.httpClient.post({
|
||||
url: url,
|
||||
headers: headers,
|
||||
url: EXAM_CORRECT_URL_POST,
|
||||
headers: EXAM_CORRECT_HEADERS,
|
||||
body: JSON.stringify(body),
|
||||
}).then(
|
||||
(response) => response.json()
|
||||
).then(
|
||||
(response) => this._processResponse(response, participant)
|
||||
(response) => this._processResponse(response, user)
|
||||
).catch((error) => {
|
||||
console.error('Error while processing response', error);
|
||||
});
|
||||
}
|
||||
|
||||
_processResponse(response, participant) {
|
||||
console.log('WIP ExamCorrect._processResponse', response, participant);
|
||||
|
||||
_processResponse(response, user) {
|
||||
console.log('WIP _processResponse', response, user);
|
||||
|
||||
if (response) {
|
||||
if (response.status === 'no-op') {
|
||||
if (response.users) {
|
||||
// TODO directly replace input value and add attr if list contains only one element
|
||||
|
||||
// TODO add event handler on links -> display name as input value and set id as attribute
|
||||
// TODO how to destroy candidate handlers?
|
||||
response.users.forEach((userCandidate) => {
|
||||
const candidateItem = document.createElement('li');
|
||||
userAsInnerHTML(candidateItem, userCandidate);
|
||||
candidateItem.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, userCandidate.id);
|
||||
|
||||
const acceptCandidateHandler = () => {
|
||||
console.log('candidate accepted');
|
||||
this._userInput.value = userCandidate['display-name'] || userCandidate.surname || userCandidate['mat-nr'];
|
||||
this._userInput.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, userCandidate.id);
|
||||
|
||||
// remove all candidates
|
||||
while (this._userInputCandidates.firstChild) {
|
||||
this._userInputCandidates.removeChild(this._userInputCandidates.firstChild);
|
||||
}
|
||||
};
|
||||
candidateItem.addEventListener('click', acceptCandidateHandler, { once: true });
|
||||
|
||||
this._userInputCandidates.appendChild(candidateItem);
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (let row of [...this._element.rows]) {
|
||||
const participantElem = row.cells.item(1);
|
||||
const participantIdent = participantElem && participantElem.getAttribute(EXAM_CORRECT_PARTICIPANT_ATTR);
|
||||
if (participantIdent === participant) {
|
||||
const userElem = row.cells.item(1);
|
||||
const userIdent = userElem && userElem.getAttribute(EXAM_CORRECT_PARTICIPANT_ATTR);
|
||||
if (userIdent === user) {
|
||||
let faIcon, ecClass;
|
||||
switch (response.status) {
|
||||
// TODO fetch update time from response and replace
|
||||
@ -171,9 +228,9 @@ export class ExamCorrect {
|
||||
faIcon = 'fa-check';
|
||||
ecClass = 'exam-correct--success';
|
||||
if (response.user) {
|
||||
participantElem.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, response.user.id);
|
||||
participantElem.innerHTML = '';
|
||||
formatUser(participantElem, response.user);
|
||||
userElem.setAttribute(EXAM_CORRECT_PARTICIPANT_ATTR, response.user.id);
|
||||
userElem.innerHTML = '';
|
||||
userAsInnerHTML(userElem, response.user);
|
||||
}
|
||||
// TODO replace results with results from response
|
||||
// TODO set edit button visibility
|
||||
@ -185,7 +242,7 @@ export class ExamCorrect {
|
||||
ecClass = 'exam-correct--error';
|
||||
// TODO show users
|
||||
if (response.users) {
|
||||
showUsers(participantElem, response.users);
|
||||
showUsers(userElem, response.users);
|
||||
}
|
||||
break;
|
||||
case 'failure':
|
||||
@ -211,10 +268,10 @@ export class ExamCorrect {
|
||||
|
||||
_removeInputEmptyClassHandler() {
|
||||
console.log('removeclass');
|
||||
if (this._participantInput.value) {
|
||||
this._participantInput.classList.remove(INPUT_EMPTY_CLASS);
|
||||
if (this._userInput.value) {
|
||||
this._userInput.classList.remove(INPUT_EMPTY_CLASS);
|
||||
} else {
|
||||
this._participantInput.addEventListener('input', this._removeInputEmptyClassHandler, { once: true });
|
||||
this._userInput.addEventListener('input', this._removeInputEmptyClassHandler, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +282,7 @@ function clearInput(inputElement) {
|
||||
inputElement.value = null;
|
||||
}
|
||||
|
||||
function formatUser(elem, user) {
|
||||
function userAsInnerHTML(elem, user) {
|
||||
if (user && user['display-name'] && user['surname']) {
|
||||
elem.innerHTML += user['display-name'].replace(new RegExp(user['surname']), `<strong>${user['surname']}</strong>`) + (user['mat-nr'] ? ` (${user['mat-nr']})` : '');
|
||||
} else {
|
||||
@ -238,7 +295,7 @@ function showUsers(elem, users) {
|
||||
elem.innerHTML = '';
|
||||
if (users) {
|
||||
for (const user of users) {
|
||||
formatUser(elem, user);
|
||||
userAsInnerHTML(elem, user);
|
||||
elem.innerHTML += '<br/>';
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -779,4 +779,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,8 @@ $newline never
|
||||
<tr .table__row>
|
||||
<td .table__td>
|
||||
<td .table__td>
|
||||
<input #exam-correct__participant type="text">
|
||||
<input #exam-correct__user type="text">
|
||||
<ul #exam-correct__user-candidates>
|
||||
$forall ExamPart{examPartNumber} <- examParts
|
||||
<td .table__td>
|
||||
^{ptsInput examPartNumber}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user