feat(exam-correct): persist results and more
This commit is contained in:
parent
a7af7ad64b
commit
53ff6298e2
@ -56,6 +56,10 @@ export class StorageManager {
|
|||||||
this._saveToLocalStorage({ ...this._getFromLocalStorage(), [key]: value });
|
this._saveToLocalStorage({ ...this._getFromLocalStorage(), [key]: value });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LOCATION.SESSION: {
|
||||||
|
this._saveToSessionStorage({ ...this._getFromSessionStorage(), [key]: value });
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LOCATION.WINDOW: {
|
case LOCATION.WINDOW: {
|
||||||
this._saveToWindow({ ...this._getFromLocalStorage(), [key]: value });
|
this._saveToWindow({ ...this._getFromLocalStorage(), [key]: value });
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -28,18 +28,12 @@ const EXAM_CORRECT_USER_DNAME_ATTR = 'exam-correct--user-dname';
|
|||||||
|
|
||||||
const INPUT_EMPTY_CLASS = 'input--invalid';
|
const INPUT_EMPTY_CLASS = 'input--invalid';
|
||||||
|
|
||||||
// TODO get from settings
|
|
||||||
const MOMENT_FORMAT = 'DD.MM.YY HH:mm:ss';
|
|
||||||
|
|
||||||
// TODO 1 for debugging only, 3 would be a better choice
|
|
||||||
const USER_VALIDATION_MIN_LENGTH = 1;
|
|
||||||
|
|
||||||
const STATUS = {
|
const STATUS = {
|
||||||
NONE: 0,
|
NONE: null,
|
||||||
SUCCESS: 1,
|
SUCCESS: 'success',
|
||||||
AMBIGUOUS: 2,
|
AMBIGUOUS: 'ambiguous',
|
||||||
ERROR: 3,
|
FAILURE: 'failure',
|
||||||
LOADING: 4,
|
LOADING: 'loading',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -49,6 +43,7 @@ const STATUS = {
|
|||||||
export class ExamCorrect {
|
export class ExamCorrect {
|
||||||
|
|
||||||
_storageManager = new StorageManager('EXAM_CORRECT', '0.0.0', { location: LOCATION.SESSION, encrypted: true });
|
_storageManager = new StorageManager('EXAM_CORRECT', '0.0.0', { location: LOCATION.SESSION, encrypted: true });
|
||||||
|
_dateFormat;
|
||||||
|
|
||||||
_element;
|
_element;
|
||||||
|
|
||||||
@ -58,6 +53,9 @@ export class ExamCorrect {
|
|||||||
_userInputCandidates;
|
_userInputCandidates;
|
||||||
_partInputs;
|
_partInputs;
|
||||||
|
|
||||||
|
_cIndices;
|
||||||
|
_lastColumnIndex;
|
||||||
|
|
||||||
constructor(element, app) {
|
constructor(element, app) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
throw new Error('Exam Correct utility cannot be setup without an element!');
|
throw new Error('Exam Correct utility cannot be setup without an element!');
|
||||||
@ -75,6 +73,9 @@ export class ExamCorrect {
|
|||||||
this._userInputCandidates = document.getElementById(EXAM_CORRECT_USER_INPUT_CANDIDATES_ID);
|
this._userInputCandidates = document.getElementById(EXAM_CORRECT_USER_INPUT_CANDIDATES_ID);
|
||||||
this._partInputs = [...this._element.querySelectorAll(`input[${EXAM_CORRECT_PART_INPUT_ATTR}]`)];
|
this._partInputs = [...this._element.querySelectorAll(`input[${EXAM_CORRECT_PART_INPUT_ATTR}]`)];
|
||||||
|
|
||||||
|
// TODO get date format by post request
|
||||||
|
this._dateFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||||
|
|
||||||
if (this._sendBtn)
|
if (this._sendBtn)
|
||||||
this._sendBtn.addEventListener('click', this._sendCorrectionHandler.bind(this));
|
this._sendBtn.addEventListener('click', this._sendCorrectionHandler.bind(this));
|
||||||
else console.error('ExamCorrect utility could not detect send button!');
|
else console.error('ExamCorrect utility could not detect send button!');
|
||||||
@ -90,6 +91,20 @@ export class ExamCorrect {
|
|||||||
if (!this._userInputCandidates) {
|
if (!this._userInputCandidates) {
|
||||||
throw new Error('ExamCorrect utility could not detect user input candidate list!');
|
throw new Error('ExamCorrect utility could not detect user input candidate list!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._cIndices = new Map(
|
||||||
|
[...this._element.querySelectorAll('[uw-exam-correct-header]')]
|
||||||
|
.map((header) => [header.getAttribute('uw-exam-correct-header'), header.cellIndex])
|
||||||
|
);
|
||||||
|
|
||||||
|
this._lastColumnIndex = this._element.querySelector('thead > tr').querySelectorAll('th').length - 1;
|
||||||
|
|
||||||
|
// show previously submitted results
|
||||||
|
const previousEntries = this._storageManager.load('entries');
|
||||||
|
if (previousEntries && previousEntries.length > 0) {
|
||||||
|
// TODO sort previous results by current sorting order first
|
||||||
|
previousEntries.forEach((entry) => this._addRow(entry));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -100,10 +115,10 @@ export class ExamCorrect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_validateUserInput() {
|
_validateUserInput() {
|
||||||
const user = this._userInput.value;
|
(!this._userInput.value) ? this._userInput.classList.add('no-value') : this._userInput.classList.remove('no-value');
|
||||||
|
|
||||||
// do nothing in case of empty or too short input
|
// do nothing in case of empty or invalid input
|
||||||
if (!user || user.length < USER_VALIDATION_MIN_LENGTH) {
|
if (!this._userInput.value || this._userInput.reportValidity && !this._userInput.reportValidity()) {
|
||||||
removeAllChildren(this._userInputCandidates);
|
removeAllChildren(this._userInputCandidates);
|
||||||
setStatus(this._userInputStatus, STATUS.NONE);
|
setStatus(this._userInputStatus, STATUS.NONE);
|
||||||
return;
|
return;
|
||||||
@ -122,7 +137,7 @@ export class ExamCorrect {
|
|||||||
setStatus(this._userInputStatus, STATUS.LOADING);
|
setStatus(this._userInputStatus, STATUS.LOADING);
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
user: user,
|
user: this._userInput.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
this._app.httpClient.post({
|
this._app.httpClient.post({
|
||||||
@ -132,13 +147,20 @@ export class ExamCorrect {
|
|||||||
}).then(
|
}).then(
|
||||||
(response) => response.json()
|
(response) => response.json()
|
||||||
).then(
|
).then(
|
||||||
(response) => this._processResponse(response, user)
|
(response) => this._processResponse(response, body.user)
|
||||||
).catch((error) => {
|
).catch((error) => {
|
||||||
console.error('Error while validating user input', error);
|
console.error('Error while validating user input', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendCorrectionHandler() {
|
_sendCorrectionHandler() {
|
||||||
|
// TODO avoid code duplication
|
||||||
|
if (this._userInput.reportValidity && !this._userInput.reportValidity()) {
|
||||||
|
removeAllChildren(this._userInputCandidates);
|
||||||
|
setStatus(this._userInput, STATUS.NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// refocus user input element for convenience
|
// refocus user input element for convenience
|
||||||
this._userInput.focus();
|
this._userInput.focus();
|
||||||
|
|
||||||
@ -154,13 +176,11 @@ export class ExamCorrect {
|
|||||||
|
|
||||||
const results = {};
|
const results = {};
|
||||||
for (const input of this._partInputs) {
|
for (const input of this._partInputs) {
|
||||||
|
if (input.reportValidity && !input.reportValidity()) {
|
||||||
|
input.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (input.value) {
|
if (input.value) {
|
||||||
if (isNaN(input.value)) {
|
|
||||||
input.classList.add('input--invalid');
|
|
||||||
input.focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
|
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
|
||||||
if (!partKey) {
|
if (!partKey) {
|
||||||
console.error('Error while parsing results: Could not detect exam part key attribute');
|
console.error('Error while parsing results: Could not detect exam part key attribute');
|
||||||
@ -173,34 +193,12 @@ export class ExamCorrect {
|
|||||||
// abort send if there are no results (after validation)
|
// abort send if there are no results (after validation)
|
||||||
if (Object.keys(results).length <= 0) return;
|
if (Object.keys(results).length <= 0) return;
|
||||||
|
|
||||||
// TODO create and use template for this
|
const rowInfo = {
|
||||||
const correctionRow = document.createElement('TR');
|
users: [{ id: userId, name: user }],
|
||||||
correctionRow.classList.add('table__row');
|
results: results,
|
||||||
const dateTD = document.createElement('TD');
|
status: STATUS.LOADING,
|
||||||
const now = moment();
|
};
|
||||||
dateTD.appendChild(document.createTextNode(now.format(MOMENT_FORMAT)));
|
this._addRow(rowInfo);
|
||||||
dateTD.setAttribute('date', moment());
|
|
||||||
dateTD.classList.add('exam-correct--local-time');
|
|
||||||
const userTD = document.createElement('TD');
|
|
||||||
userTD.appendChild(document.createTextNode(user));
|
|
||||||
userTD.setAttribute(EXAM_CORRECT_USER_ATTR, user);
|
|
||||||
const partTDs = this._partInputs.map((input) => {
|
|
||||||
const partTD = document.createElement('TD');
|
|
||||||
const partKey = input.getAttribute(EXAM_CORRECT_PART_INPUT_ATTR);
|
|
||||||
if (results[partKey])
|
|
||||||
partTD.appendChild(document.createTextNode(results[partKey]));
|
|
||||||
return partTD;
|
|
||||||
});
|
|
||||||
const statusTD = document.createElement('TD');
|
|
||||||
const statusDiv = document.createElement('DIV');
|
|
||||||
statusDiv.classList.add('exam-correct--loading');
|
|
||||||
statusTD.appendChild(statusDiv);
|
|
||||||
[dateTD,userTD,...partTDs, statusTD].forEach((td) => {
|
|
||||||
td.classList.add('table__td');
|
|
||||||
correctionRow.appendChild(td);
|
|
||||||
});
|
|
||||||
const tableBody = this._element.querySelector(`tbody:not(#${EXAM_CORRECT_INPUT_BODY_ID})`);
|
|
||||||
tableBody.insertBefore(correctionRow, tableBody.firstChild);
|
|
||||||
|
|
||||||
// clear inputs on validation success
|
// clear inputs on validation success
|
||||||
this._clearUserInput();
|
this._clearUserInput();
|
||||||
@ -218,7 +216,7 @@ export class ExamCorrect {
|
|||||||
}).then(
|
}).then(
|
||||||
(response) => response.json()
|
(response) => response.json()
|
||||||
).then(
|
).then(
|
||||||
(response) => this._processResponse(response, user, results)
|
(response) => this._processResponse(response, body.user, results)
|
||||||
).catch((error) => {
|
).catch((error) => {
|
||||||
console.error('Error while processing response', error);
|
console.error('Error while processing response', error);
|
||||||
});
|
});
|
||||||
@ -270,17 +268,27 @@ export class ExamCorrect {
|
|||||||
this._userInputCandidates.appendChild(candidateItem);
|
this._userInputCandidates.appendChild(candidateItem);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// TODO what to do in this case?
|
||||||
setStatus(this._userInputStatus, STATUS.FAILURE);
|
setStatus(this._userInputStatus, STATUS.FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const savedEntries = this._storageManager.load('entries') || [];
|
||||||
|
let newEntry = {
|
||||||
|
users: null,
|
||||||
|
results: null,
|
||||||
|
status: STATUS.FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('response', response);
|
||||||
|
|
||||||
for (let row of [...this._element.rows]) {
|
for (let row of [...this._element.rows]) {
|
||||||
const userElem = row.cells.item(1);
|
let userElem = row.cells.item(this._cIndices.get('user'));
|
||||||
const userIdent = userElem && userElem.getAttribute(EXAM_CORRECT_USER_ATTR);
|
const userIdent = userElem && userElem.getAttribute(EXAM_CORRECT_USER_ATTR); // TODO use other attribute identifier
|
||||||
if (userIdent === user) {
|
if (userIdent === user) {
|
||||||
let status = STATUS.ERROR;
|
let status = STATUS.FAILURE;
|
||||||
switch (response.status) {
|
switch (response.status) {
|
||||||
// TODO fetch update time from response and replace
|
// TODO fetch update time from response and replace
|
||||||
case 'success':
|
case 'success':
|
||||||
@ -289,9 +297,11 @@ export class ExamCorrect {
|
|||||||
userElem.setAttribute(EXAM_CORRECT_USER_ATTR, response.user.id);
|
userElem.setAttribute(EXAM_CORRECT_USER_ATTR, response.user.id);
|
||||||
userElem.innerHTML = userToHTML(response.user);
|
userElem.innerHTML = userToHTML(response.user);
|
||||||
const timeElem = row.cells.item(0);
|
const timeElem = row.cells.item(0);
|
||||||
timeElem.innerHTML = moment(response.time).format(MOMENT_FORMAT);
|
timeElem.innerHTML = moment(response.time).format(this._dateFormat);
|
||||||
timeElem.classList.remove('exam-correct--local-time');
|
timeElem.classList.remove('exam-correct--local-time');
|
||||||
// TODO special style for server time?
|
// TODO special style for server time?
|
||||||
|
newEntry.users = [response.user];
|
||||||
|
newEntry.results = response.results;
|
||||||
}
|
}
|
||||||
// TODO replace results with results from response
|
// TODO replace results with results from response
|
||||||
// TODO set edit button visibility
|
// TODO set edit button visibility
|
||||||
@ -301,11 +311,15 @@ export class ExamCorrect {
|
|||||||
// TODO set edit button visibility
|
// TODO set edit button visibility
|
||||||
status = STATUS.AMBIGUOUS;
|
status = STATUS.AMBIGUOUS;
|
||||||
if (response.users) {
|
if (response.users) {
|
||||||
this._showUserList(row, response.users, results);
|
userElem = this._showUserList(row, response.users, results);
|
||||||
|
newEntry.users = response.users;
|
||||||
|
newEntry.results = results;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'failure':
|
case 'failure':
|
||||||
status = STATUS.FAILURE;
|
status = STATUS.FAILURE;
|
||||||
|
newEntry.users = [user];
|
||||||
|
newEntry.results = results;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO show tooltip with 'invalid response'
|
// TODO show tooltip with 'invalid response'
|
||||||
@ -315,9 +329,17 @@ export class ExamCorrect {
|
|||||||
row.querySelectorAll('.exam-correct--loading').forEach((elem) => {
|
row.querySelectorAll('.exam-correct--loading').forEach((elem) => {
|
||||||
setStatus(elem, status);
|
setStatus(elem, status);
|
||||||
});
|
});
|
||||||
break;
|
newEntry.status = status || STATUS.FAILURE;
|
||||||
|
savedEntries.push(newEntry);
|
||||||
|
this._storageManager.save('entries', savedEntries);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insert a new row if no previous entry was found
|
||||||
|
// this._addRow(newEntry);
|
||||||
|
// savedEntries.unshift(newEntry);
|
||||||
|
// this._storageManager.save('entries', savedEntries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +353,10 @@ export class ExamCorrect {
|
|||||||
|
|
||||||
// TODO better name
|
// TODO better name
|
||||||
_showUserList(row, users, results) {
|
_showUserList(row, users, results) {
|
||||||
const userElem = row.cells.item(1);
|
let userElem = row.cells.item(this._cIndices.get('user'));
|
||||||
|
if (!userElem) {
|
||||||
|
userElem = document.createElement('TD');
|
||||||
|
}
|
||||||
if (users) {
|
if (users) {
|
||||||
removeAllChildren(userElem);
|
removeAllChildren(userElem);
|
||||||
const list = document.createElement('UL');
|
const list = document.createElement('UL');
|
||||||
@ -352,12 +377,14 @@ export class ExamCorrect {
|
|||||||
} else {
|
} else {
|
||||||
console.error('Unable to show users from invalid response');
|
console.error('Unable to show users from invalid response');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return userElem;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rowToRequest(row, listItem, results) {
|
_rowToRequest(row, listItem, results) {
|
||||||
const now = moment();
|
const now = moment();
|
||||||
const timeElem = row.cells.item(0);
|
const timeElem = row.cells.item(0);
|
||||||
timeElem.innerHTML = now.format(MOMENT_FORMAT);
|
timeElem.innerHTML = now.format(this._dateFormat);
|
||||||
timeElem.classList.add('exam-correct--local-time');
|
timeElem.classList.add('exam-correct--local-time');
|
||||||
const userElem = row.cells.item(1);
|
const userElem = row.cells.item(1);
|
||||||
const statusElem = row.querySelector('.exam-correct--ambiguous');
|
const statusElem = row.querySelector('.exam-correct--ambiguous');
|
||||||
@ -377,13 +404,29 @@ export class ExamCorrect {
|
|||||||
(response) => response.json()
|
(response) => response.json()
|
||||||
).then((response) => {
|
).then((response) => {
|
||||||
switch (response.status) {
|
switch (response.status) {
|
||||||
case 'success':
|
case 'success': {
|
||||||
userElem.innerHTML = userToHTML(response.user);
|
userElem.innerHTML = userToHTML(response.user);
|
||||||
// TODO replace part results with results from server
|
// TODO replace part results with results from server
|
||||||
timeElem.innerHTML = moment(response.time).format(MOMENT_FORMAT);
|
timeElem.innerHTML = moment(response.time).format(this._dateFormat);
|
||||||
timeElem.classList.remove('exam-correct--local-time');
|
timeElem.classList.remove('exam-correct--local-time');
|
||||||
setStatus(statusElem, STATUS.SUCCESS);
|
setStatus(statusElem, STATUS.SUCCESS);
|
||||||
|
const savedEntries = this._storageManager.load('entries');
|
||||||
|
for (let i = 0; i < savedEntries.length; i++) {
|
||||||
|
for (let user of savedEntries[i].users) {
|
||||||
|
if (user.id === response.user.id) {
|
||||||
|
savedEntries[i] = {
|
||||||
|
users: [response.user],
|
||||||
|
results: response.results,
|
||||||
|
status: STATUS.SUCCESS,
|
||||||
|
date: response.time,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._storageManager.save('entries', savedEntries);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// non-success response on request with a uuid => panic and ignore for now
|
// non-success response on request with a uuid => panic and ignore for now
|
||||||
}
|
}
|
||||||
@ -392,6 +435,60 @@ export class ExamCorrect {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_addRow(rowInfo) {
|
||||||
|
console.log('rowInfo', rowInfo);
|
||||||
|
// TODO create and use template for this
|
||||||
|
const newRow = document.createElement('TR');
|
||||||
|
newRow.classList.add('table__row');
|
||||||
|
|
||||||
|
const cells = new Map();
|
||||||
|
|
||||||
|
const dateCell = document.createElement('TD');
|
||||||
|
const date = rowInfo.date ? moment(rowInfo.date) : moment();
|
||||||
|
dateCell.appendChild(document.createTextNode(date.format(this._dateFormat)));
|
||||||
|
dateCell.setAttribute('date', date.utc().format());
|
||||||
|
if (!rowInfo.date) dateCell.classList.add('exam-correct--local-time');
|
||||||
|
cells.set(this._cIndices.get('date'), dateCell);
|
||||||
|
|
||||||
|
let userCell = document.createElement('TD');
|
||||||
|
if (!rowInfo.users || rowInfo.users.length === 0) {
|
||||||
|
console.error('Found rowInfo without users info!');
|
||||||
|
} else if (rowInfo.users.length === 1) {
|
||||||
|
const user = rowInfo.users[0];
|
||||||
|
userCell.innerHTML = userToHTML(user);
|
||||||
|
userCell.setAttribute(EXAM_CORRECT_USER_ATTR, user.id || user.name);
|
||||||
|
} else {
|
||||||
|
userCell = this._showUserList(newRow, rowInfo.users, rowInfo.results);
|
||||||
|
}
|
||||||
|
cells.set(this._cIndices.get('user'), userCell);
|
||||||
|
|
||||||
|
for (const [partKey, partResult] of Object.entries(rowInfo.results)) {
|
||||||
|
const cellIndex = this._cIndices.get(partKey);
|
||||||
|
if (cellIndex === undefined) {
|
||||||
|
console.error('Could not determine cell index from part key!');
|
||||||
|
} else {
|
||||||
|
const partCell = document.createElement('TD');
|
||||||
|
partCell.innerHTML = partResult;
|
||||||
|
cells.set(cellIndex, partCell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusCell = document.createElement('TD');
|
||||||
|
const statusDiv = document.createElement('DIV');
|
||||||
|
setStatus(statusDiv, rowInfo.status);
|
||||||
|
statusCell.appendChild(statusDiv);
|
||||||
|
cells.set(this._cIndices.get('status'), statusCell);
|
||||||
|
|
||||||
|
for (let i = 0; i <= this._lastColumnIndex; i++) {
|
||||||
|
const cell = cells.get(i) || document.createElement('TD');
|
||||||
|
cell.classList.add('table__td');
|
||||||
|
newRow.appendChild(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableBody = this._element.querySelector(`tbody:not(#${EXAM_CORRECT_INPUT_BODY_ID})`);
|
||||||
|
insertAsFirstChild(newRow, tableBody);
|
||||||
|
}
|
||||||
|
|
||||||
_clearUserInput() {
|
_clearUserInput() {
|
||||||
removeAllChildren(this._userInputCandidates);
|
removeAllChildren(this._userInputCandidates);
|
||||||
clearInput(this._userInput);
|
clearInput(this._userInput);
|
||||||
@ -406,16 +503,20 @@ export class ExamCorrect {
|
|||||||
function clearInput(inputElement) {
|
function clearInput(inputElement) {
|
||||||
inputElement.value = null;
|
inputElement.value = null;
|
||||||
}
|
}
|
||||||
|
function insertAsFirstChild(elementToInsert, parentElement) {
|
||||||
|
parentElement.insertBefore(elementToInsert, parentElement.firstChild);
|
||||||
|
}
|
||||||
function removeAllChildren(element) {
|
function removeAllChildren(element) {
|
||||||
while (element.firstChild) {
|
while (element.firstChild) {
|
||||||
element.removeChild(element.firstChild);
|
element.removeChild(element.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function userToHTML(user) {
|
function userToHTML(user) {
|
||||||
if (user && user['display-name'] && user['surname']) {
|
if (user && user['display-name'] && user['surname']) {
|
||||||
return user['display-name'].replace(new RegExp(user['surname']), `<strong>${user['surname']}</strong>`) + (user['mat-nr'] ? ` (${user['mat-nr']})` : '');
|
return user['display-name'].replace(new RegExp(user['surname']), `<strong>${user['surname']}</strong>`) + (user['mat-nr'] ? ` (${user['mat-nr']})` : '');
|
||||||
|
} else if (user && user.name) {
|
||||||
|
return user.name;
|
||||||
} else {
|
} else {
|
||||||
console.error('Unable to format invalid user response');
|
console.error('Unable to format invalid user response');
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
input.input--invalid
|
$exam-correct--input-status-margin: 10px
|
||||||
border: 2px solid var(--color-error)
|
|
||||||
|
[uw-exam-correct] input:invalid:not(.no-value)
|
||||||
|
border: 2px solid var(--color-error)
|
||||||
|
|
||||||
.exam-correct--input-status
|
.exam-correct--input-status
|
||||||
$exam-correct--input-status-margin: 10px
|
|
||||||
|
|
||||||
input
|
input
|
||||||
width: calc(100% - 18em/14 - #{$exam-correct--input-status-margin})
|
width: calc(100% - 18em/14 - #{$exam-correct--input-status-margin})
|
||||||
i
|
i
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user