diff --git a/frontend/src/utils/exam-correct/exam-correct.js b/frontend/src/utils/exam-correct/exam-correct.js index 45f967ee7..70a9bdb63 100644 --- a/frontend/src/utils/exam-correct/exam-correct.js +++ b/frontend/src/utils/exam-correct/exam-correct.js @@ -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']), `${user['surname']}`) + (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 += '
'; } } else { diff --git a/records.json b/records.json index 00fdc183c..9e7f6c03d 100644 --- a/records.json +++ b/records.json @@ -779,4 +779,4 @@ } } ] -} +} \ No newline at end of file diff --git a/templates/exam-correct.hamlet b/templates/exam-correct.hamlet index ab6645ba5..b825dda09 100644 --- a/templates/exam-correct.hamlet +++ b/templates/exam-correct.hamlet @@ -26,7 +26,8 @@ $newline never - + +