@dbp-topics/formalize
Version:
[GitLab Repository](https://gitlab.tugraz.at/dbp/formalize/formalize) | [npmjs package](https://www.npmjs.com/package/@dbp-topics/formalize) | [Unpkg CDN](https://unpkg.com/browse/@dbp-topics/formalize/) | [Formalize Bundle](https://gitlab.tugraz.at/dbp/f
1,485 lines (1,300 loc) • 89.3 kB
JavaScript
import {createInstance} from './i18n.js';
import {css, unsafeCSS, html} from 'lit';
import {ScopedElementsMixin} from '@open-wc/scoped-elements';
import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
import {Icon, MiniSpinner, LoadingButton, getIconSVGURL} from '@dbp-toolkit/common';
import * as commonUtils from '@dbp-toolkit/common/utils';
import * as commonStyles from '@dbp-toolkit/common/styles';
import {classMap} from 'lit/directives/class-map.js';
import {Activity} from './activity.js';
import {TabulatorFull as Tabulator} from 'tabulator-tables';
import MicroModal from './micromodal.es';
import {name as pkgName} from './../package.json';
import * as fileHandlingStyles from './styles';
import * as tabulatorStyles from './tabulator-table-styles';
import metadata from './dbp-formalize-show-registrations.metadata.json';
import xss from 'xss';
import {send} from '@dbp-toolkit/common/notification';
import {getStackTrace} from '@dbp-toolkit/common/error';
/**
* Imports xlsx plugin
*
* @returns {object} xlsx
*/
async function importXLSX() {
return await import('xlsx');
}
/**
* Imports jsPDF and include jspdf-autotable plugin
*
* @returns {object} jspdf
*/
async function importJsPDF() {
let jspdf = await import('jspdf');
let autotable = await import('jspdf-autotable');
autotable.applyPlugin(jspdf.jsPDF);
return jspdf;
}
class ShowRegistrations extends ScopedElementsMixin(DBPLitElement) {
constructor() {
super();
this._i18n = createInstance();
this.lang = this._i18n.language;
this.auth = {};
this.entryPointUrl = '';
this.activity = new Activity(metadata);
this.coursesTable = null;
this.submissionsTable = null;
this.showSubmissionsTable = false;
this.submissionsColumns = [];
this.submissionsColumnsUpdated = false;
this.initateOpenAdditionalMenu = false;
this.initateOpenAdditionalSearchMenu = false;
this.boundCloseAdditionalMenuHandler = this.hideAdditionalMenu.bind(this);
this.boundCloseAdditionalSearchMenuHandler = this.hideAdditionalSearchMenu.bind(this);
this.boundPressEnterAndSubmitSearchHandler = this.pressEnterAndSubmitSearch.bind(this);
this.activeCourse = '';
this.currentRow = null;
this.currentBeautyId = 0;
this.totalNumberOfItems = 0;
this.isPrevEnabled = false;
this.isNextEnabled = false;
this.storeSession = true;
this.loadingCourseTable = false;
this.loadingSubmissionTable = false;
this.dataLoaded = false;
this.modalContentHeight = 0;
this.loadCourses = true;
this.hasPermissions = true;
this.hiddenColumns = false;
}
static get scopedElements() {
return {
'dbp-icon': Icon,
'dbp-mini-spinner': MiniSpinner,
'dbp-loading-button': LoadingButton
};
}
static get properties() {
return {
...super.properties,
lang: {type: String},
auth: {type: Object},
entryPointUrl: {type: String, attribute: 'entry-point-url'},
coursesTable: {type: Object, attribute: false},
submissionsTable: {type: Object, attribute: false},
showSubmissionsTable: {type: Boolean, attribute: false},
submissionsColumns: {type: Array, attribute: false},
submissionsColumnsUpdated: {type: Boolean, attribute: false},
isPrevEnabled: {type: Boolean, attribute: false},
isNextEnabled: {type: Boolean, attribute: false},
currentBeautyId: {type: Number, attribute: false},
loadingCourseTable: {type: Boolean, attribute: false},
loadingSubmissionTable: {type: Boolean, attribute: false},
modalContentHeight: {type: Number, attribute: false},
loadCourses: {type: Boolean, attribute: false},
hasPermissions: {type: Boolean, attribute: false},
hiddenColumns: {type: Boolean, attribute: false}
};
}
disconnectedCallback() {
super.disconnectedCallback();
this.submissionsTable.off('dataProcesseds');
this.submissionsTable.off('pageLoaded');
document.removeEventListener('keyup', this.boundPressEnterAndSubmitSearchHandler);
}
/**
* Converts a timestamp to a readable date
*
* @param value
* @returns {string} xlsx year-month-date hours:minutes
*/
humanReadableDate(value) {
const d = Date.parse(value);
const timestamp = new Date(d);
const year = timestamp.getFullYear();
const month = ('0' + (timestamp.getMonth() + 1)).slice(-2);
const date = ('0' + timestamp.getDate()).slice(-2);
const hours = ('0' + timestamp.getHours()).slice(-2);
const minutes = ('0' + timestamp.getMinutes()).slice(-2);
return year + '-' + month + '-' + date + ' ' + hours + ':' + minutes;
}
connectedCallback() {
super.connectedCallback();
const i18n = this._i18n;
this._loginStatus = '';
this._loginState = [];
this.updateComplete.then(() => {
const that = this;
// see: http://tabulator.info/docs/5.1
this.coursesTable = new Tabulator(this._('#courses-table'), {
layout: 'fitColumns',
selectable: false,
placeholder: i18n.t('show-registrations.no-data'),
pagination: true,
paginationMode: 'local',
paginationSize: 10,
paginationSizeSelector: true,
locale: true,
columnDefaults: {
vertAlign: 'middle',
resizable: false
},
columns: [
{
title: 'ID',
field: 'id',
widthGrow: 1,
maxWidth: 50,
},
{
title: 'Name',
field: 'name',
widthGrow: 2,
},
{
title: i18n.t('show-registrations.date'),
field: 'date',
widthGrow: 2,
formatter: function(cell, formatterParams, onRendered) {
return that.humanReadableDate(cell.getValue());
},
visible: false,
},
{
title: '',
maxWidth: 45,
field: 'actionButton',
formatter: 'html',
headerSort: false,
}
],
langs: {
'en': {
'pagination': {
'page_size': 'Page size',
'page_size_title': 'Page size',
'first': '<span class="mobile-hidden">First</span>',
'first_title': 'First Page',
'last': '<span class="mobile-hidden">Last</span>',
'last_title': 'Last Page',
'prev': '<span class="mobile-hidden">Prev</span>',
'prev_title': 'Prev Page',
'next': '<span class="mobile-hidden">Next</span>',
'next_title': 'Next Page'
}
},
'de': {
'pagination': {
'page_size': 'Einträge pro Seite',
'page_size_title': 'Einträge pro Seite',
'first': '<span class="mobile-hidden">Erste</span>',
'first_title': 'Erste Seite',
'last': '<span class="mobile-hidden">Letzte</span>',
'last_title': 'Letzte Seite',
'prev': '<span class="mobile-hidden">Vorherige</span>',
'prev_title': 'Vorherige Seite',
'next': '<span class="mobile-hidden">Nächste</span>',
'next_title': 'Nächste Seite'
}
}
}
});
const actionsButtons = (cell, formatterParams) => {
let id = cell.getData()['id'];
let btn = this.createScopedElement('dbp-icon');
btn.setAttribute('name', 'keyword-research');
btn.setAttribute('id', id);
btn.classList.add('open-modal-icon');
btn.addEventListener('click', event => {
this.requestDetailedSubmission(cell.getRow(), cell.getRow().getData());
event.stopPropagation();
});
let div = this.createScopedElement('div');
div.appendChild(btn);
div.classList.add('actions-buttons');
return div;
};
let customAccessor = (value, data, type, params, column, row) => {
return this.humanReadableDate(value);
};
let paginationElement = this._('.tabulator-paginator');
this.submissionsTable = new Tabulator(this._('#submissions-table'), {
layout: 'fitDataFill',
selectable: true,
selectablePersistence: false,
placeholder: i18n.t('show-registrations.no-data'),
columnDefaults: {
vertAlign: 'middle',
resizable: false
},
pagination: true,
paginationMode: 'local',
paginationSize: 10,
paginationSizeSelector: true,
paginationElement: paginationElement,
autoColumns: true,
downloadRowRange: 'selected',
locale: true,
langs: {
'en': {
'pagination': {
'page_size': 'Page size',
'page_size_title': 'Page size',
'first': '<span class="mobile-hidden">First</span>',
'first_title': 'First Page',
'last': '<span class="mobile-hidden">Last</span>',
'last_title': 'Last Page',
'prev': '<span class="mobile-hidden">Prev</span>',
'prev_title': 'Prev Page',
'next': '<span class="mobile-hidden">Next</span>',
'next_title': 'Next Page'
}
},
'de': {
'pagination': {
'page_size': 'Einträge pro Seite',
'page_size_title': 'Einträge pro Seite',
'first': '<span class="mobile-hidden">Erste</span>',
'first_title': 'Erste Seite',
'last': '<span class="mobile-hidden">Letzte</span>',
'last_title': 'Letzte Seite',
'prev': '<span class="mobile-hidden">Vorherige</span>',
'prev_title': 'Vorherige Seite',
'next': '<span class="mobile-hidden">Nächste</span>',
'next_title': 'Nächste Seite'
}
}
},
autoColumnsDefinitions: [
{
title: '',
hozAlign: 'center',
field: 'no_display_1',
download: false,
headerSort: false,
visible: true,
formatter: actionsButtons,
frozen: true
},
{
minWidth: 150,
field: 'dateCreated',
title: i18n.t('show-registrations.creation-date'),
hozAlign: 'left',
sorter: (a, b, aRow, bRow, column, dir, sorterParams) => {
const a_timestamp = Date.parse(a);
const b_timestamp = Date.parse(b);
return a_timestamp - b_timestamp;
},
formatter: (cell, formatterParams, onRendered) => {
return this.humanReadableDate(cell.getValue());
},
accessorParams: {},
accessor: customAccessor
},
{
field: 'id',
title: 'ID',
download: false,
visible: false
},
{
field: 'id_',
title: 'ID',
hozAlign: 'center',
visible: false,
download: false
}
]
});
this.submissionsTable.on('dataProcessed', this.dataProcessedSubmissionTableFunction.bind(this));
this.submissionsTable.on("pageLoaded", function(pageno){
if (that._('#searchbar')) {
setTimeout(function () {
that._('#searchbar').scrollIntoView({behavior: 'smooth', block: 'start'});
}, 0);
}
});
document.addEventListener('keyup', this.boundPressEnterAndSubmitSearchHandler);
});
}
/**
* An event function,
* if we cant load table settings, then update the header list
*
*/
dataProcessedSubmissionTableFunction() {
if (this.submissionsTable !== null) {
if (!this.getSubmissionTableSettings()) {
this.updateTableHeaderList();
}
}
console.log("DATALOADED\n");
}
update(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
switch (propName) {
case 'lang':
this._i18n.changeLanguage(this.lang);
if (this.coursesTable) {
this.coursesTable.setLocale(this.lang);
}
if (this.submissionsTable) {
this.submissionsTable.setLocale(this.lang);
}
break;
case 'auth':
this._updateAuth();
break;
}
});
super.update(changedProperties);
}
/**
* Sends an analytics error event
*
* @param category
* @param action
* @param information
* @param responseData
*/
async sendErrorAnalyticsEvent(category, action, information, responseData = {}) {
let responseBody = {};
// Use a clone of responseData to prevent "Failed to execute 'json' on 'Response': body stream already read"
// after this function, but still a TypeError will occur if .json() was already called before this function
try {
responseBody = await responseData.clone().json();
} catch (e) {
responseBody = responseData; // got already decoded data
}
const data = {
status: responseData.status || '',
url: responseData.url || '',
description: responseBody['hydra:description'] || '',
errorDetails: responseBody['relay:errorDetails'] || '',
information: information,
// get 5 items from the stack trace
stack: getStackTrace().slice(1, 6)
};
this.sendSetPropertyEvent('analytics-event', {
category: category,
action: action,
name: JSON.stringify(data)
});
}
/**
* Request a re-render every time isLoggedIn()/isLoading() changes
*/
_updateAuth() {
this._loginStatus = this.auth['login-status'];
let newLoginState = [this.isLoggedIn(), this.isLoading()];
if (this._loginState.toString() !== newLoginState.toString()) {
this.requestUpdate();
}
this._loginState = newLoginState;
}
/**
* Returns if a person is set in or not
*
* @returns {boolean} true or false
*/
isLoggedIn() {
return (this.auth.person !== undefined && this.auth.person !== null);
}
/**
* Returns true if a person has successfully logged in
*
* @returns {boolean} true or false
*/
isLoading() {
if (this._loginStatus === 'logged-out')
return false;
return (!this.isLoggedIn() && this.auth.token !== undefined);
}
/**
* Send a fetch to given url with given options
*
* @param url
* @param options
* @returns {object} response (error or result)
*/
async httpGetAsync(url, options) {
let response = await fetch(url, options).then(result => {
if (!result.ok) throw result;
return result;
}).catch(error => {
return error;
});
return response;
}
throwSomethingWentWrongNotification() {
const i18n = this._i18n;
send({
summary: i18n.t('show-registrations.something-went-wrong-title'),
body: i18n.t('show-registrations.something-went-wrong-body'),
type: 'danger',
timeout: 5
});
}
/**
* Gets the list of courses
*
* @returns {object} response
*/
async getListOfAllCourses() {
const i18n = this._i18n;
//TODO cache this data
let dataList = [];
let response = await this.getAllSubmissions();
if (!response) {
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'NoResponse', '');
this.throwSomethingWentWrongNotification();
return;
}
if (response.status !== 200) {
if (response.status === 403) {
this.hasPermissions = false;
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'NoPermission', '', response);
send({
summary: i18n.t('show-registrations.load-courses-no-permission-title'),
body: i18n.t('show-registrations.load-courses-no-permission-body'),
type: 'danger',
timeout: 5
});
return;
}
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'SomeWentWrong', '', response);
this.throwSomethingWentWrongNotification();
return;
}
let data = [];
try {
data = await response.json();
} catch (e) {
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'WrongResponse', e);
this.throwSomethingWentWrongNotification();
return;
}
if (!data || !data['hydra:member']) {
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'WrongData', '');
this.throwSomethingWentWrongNotification();
return;
}
let id = 1;
let courses = [];
for (let x = 0; x <= data["hydra:member"].length; x++) {
if (x === data['hydra:member'].length) {
this.coursesTable.setData(dataList);
this.coursesTable.setLocale(this.lang);
this.dataLoaded = true;
return;
}
let entry = data['hydra:member'][x];
try {
let name = entry['form'];
// Load form only one time
if (!name || courses.length > 0 && courses.includes(name)) {
continue;
}
let date = entry['dateCreated'];
// create 'show form' button
let icon = this.createScopedElement('dbp-icon');
icon.setAttribute('name', 'chevron-right');
icon.setAttribute('title', i18n.t('show-registrations.open-forms'));
let btn = this.createScopedElement('dbp-button');
btn.classList.add('button', 'courses-btn');
btn.addEventListener('click', async event => {
this.loadingSubmissionTable = true;
await this.requestAllCourseSubmissions(name);
this.loadingSubmissionTable = false;
event.stopPropagation();
});
btn.appendChild(icon);
let div = this.createScopedElement('div');
div.classList.add('button-wrapper');
div.appendChild(btn);
let course = {id: id, name: name, date: date, actionButton: div};
id++;
courses.push(name);
dataList.push(course);
} catch (e) {
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'ErrorInDataCreation', e);
}
}
}
/**
* Gets the list of submissions
*
* @returns {object} response
*/
async getAllSubmissions() {
let response;
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/ld+json',
Authorization: 'Bearer ' + this.auth.token
}
};
response = await this.httpGetAsync(this.entryPointUrl + '/formalize/submissions', options);
return response;
}
/**
* Gets a submission for a given identifier
*
* @param identifier
* @returns {object} response
*/
async getSubmissionForId(identifier) {
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/ld+json',
Authorization: 'Bearer ' + this.auth.token
}
};
return await this.httpGetAsync(this.entryPointUrl + '/formalize/submissions/' + identifier, options);
}
/**
* Initiate getListOfAllCourses and set Loading
*/
async requestCourses() {
if (!this.dataLoaded) {
this.loadingCourseTable = true;
await this.getListOfAllCourses();
this.loadingCourseTable = false;
}
}
/**
* Gets the list of submissions for a specific course
*
* @param {string} name
*/
async requestAllCourseSubmissions(name) {
const i18n = this._i18n;
let dataList2 = [];
let response = await this.getAllSubmissions();
this.submissionsColumns = [];
if (!response) {
this.sendErrorAnalyticsEvent('requestAllCourseSubmissions', 'NoResponse', '');
this.throwSomethingWentWrongNotification();
return;
}
if (response.status !== 200) {
if (response.status === 403) {
this.hasPermissions = false;
this.sendErrorAnalyticsEvent('requestAllCourseSubmissions', 'NoPermission', '', response);
send({
summary: i18n.t('show-registrations.load-courses-no-permission-title'),
body: i18n.t('show-registrations.load-courses-no-permission-body'),
type: 'danger',
timeout: 5
});
return;
}
this.sendErrorAnalyticsEvent('requestAllCourseSubmissions', 'NoResponse', '', response);
this.throwSomethingWentWrongNotification();
return;
}
let data = [];
try {
data = await response.json();
} catch (e) {
this.sendErrorAnalyticsEvent('requestAllCourseSubmissions', 'WrongResponse', e);
this.throwSomethingWentWrongNotification();
return;
}
if (!data || !data['hydra:member']) {
this.showSubmissionsTable = true;
this.sendErrorAnalyticsEvent('requestAllCourseSubmissions', 'WrongData', '');
this.throwSomethingWentWrongNotification();
return;
}
let itemsCount = 0;
for (let x = 0; x <= data["hydra:member"].length; x++) {
if (x === data['hydra:member'].length) {
this.activeCourse = name;
this.submissionsTable.setData(dataList2);
this.submissionsTable.setLocale(this.lang);
this.updateSubmissionTable();
this.showSubmissionsTable = true;
const that = this;
setTimeout(function() {
if (that._('.subheadline')) {
// that._('.subheadline').scrollIntoView({behavior: 'smooth', block: 'start'});
}
}, 10);
return;
}
let entry = data['hydra:member'][x];
let id = entry['@id'].split('/')[3];
let date = entry['dateCreated'];
try {
if (entry && entry['form'] !== name)
continue;
let json = JSON.parse(entry['dataFeedElement']);
let jsonFirst = {};
jsonFirst['id'] = id;
jsonFirst['no_display_1'] = '';
jsonFirst['id_'] = itemsCount + 1;
jsonFirst['dateCreated'] = date;
json = Object.assign(jsonFirst, json);
dataList2.push(json);
itemsCount++;
} catch (e) {
this.sendErrorAnalyticsEvent('LoadListOfAllCourses', 'ErrorInDataCreation', e);
}
this.totalNumberOfItems = itemsCount;
}
}
/**
* Gets the detaildata of a specific row
*
* @param row
* @param data
*/
requestDetailedSubmission(row, data) {
if (!this._('.detailed-submission-modal-content-wrapper'))
return;
this._('.detailed-submission-modal-content-wrapper').innerHTML = '';
if (!this._('#apply-col-settings'))
return;
let colSettings = this._('#apply-col-settings').checked;
let identifier = data['id_'];
if (!colSettings) {
let cells = data;
for (let i = 0; i < Object.keys(cells).length; i++) {
let key = Object.keys(cells)[i];
if (key.includes('no_display') || key.includes('id')) {
continue;
} else if (key.includes('dateCreated') && (cells[key] !== '')) {
let title = this.submissionsTable.getColumn('dateCreated').getDefinition().title;
title = title === '' ? key : title;
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-left'>` + title + `:</div>`;
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'>` + this.humanReadableDate(cells[key]);
+`</div>`;
continue;
}
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-left'>` + xss(key) + `:</div>`;
if (cells[key] !== '') {
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'>` + xss(cells[key]) + `</div>`;
} else {
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'></div>`;
}
}
} else {
// If checkbox checked
let cells = data;
for (let i = 0; i < Object.keys(cells).length; i++) {
let key = Object.keys(cells)[i];
let isVisible = true;
if (this.submissionsTable.getColumn(key)) {
isVisible = window.getComputedStyle(this.submissionsTable.getColumn(key).getElement()).display === 'none' ? false : true;
}
if (key.includes('no_display') || key.includes('id') || !isVisible) {
continue;
} else if (key.includes('dateCreated') && (cells[key] !== '')) {
let title = this.submissionsTable.getColumn('dateCreated').getDefinition().title;
title = title === '' ? key : title;
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-left'>` + title + `:</div>`;
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'>` + this.humanReadableDate(cells[key]);
+`</div>`;
continue;
}
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-left'>` + xss(key) + `:</div>`;
if (cells[key] !== '') {
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'>` + xss(cells[key]) + `</div>`;
} else {
this._('.detailed-submission-modal-content-wrapper').innerHTML += `<div class='element-right'></div>`;
}
}
}
if (this._('.detailed-submission-modal-content-wrapper > div:first-child'))
this._('.detailed-submission-modal-content-wrapper > div:first-child').classList.add('first');
if (this._('.detailed-submission-modal-content-wrapper > div:nth-child(2)'))
this._('.detailed-submission-modal-content-wrapper > div:nth-child(2)').classList.add('first');
this.currentRow = row;
this.currentBeautyId = identifier;
this.isPrevEnabled = identifier !== 1;
this.isNextEnabled = (identifier + 1) <= this.submissionsTable.getDataCount();
this.showDetailedModal();
this.modalContentHeight = this._('#detailed-submission-modal-box > .modal-header').offsetHeight +
this._('#detailed-submission-modal-box > .modal-footer').offsetHeight;
this._('.detailed-submission-modal-content-wrapper').setAttribute('style', 'max-height: calc(100vH - ' + this.modalContentHeight + 'px);');
}
/**
* Export the specific table
*
* @param e
*/
async exportSubmissionTable(e) {
let exportInput = this._('#export-select');
if (!exportInput)
return;
let exportValue = exportInput.value;
if (!exportValue || exportValue === '')
return;
if (e)
e.stopPropagation();
switch (exportValue) {
case 'csv':
this.exportCSV();
break;
case 'pdf':
this.exportPdf();
break;
case 'excel':
this.exportXLSX();
break;
default:
break;
}
exportInput.value = '-';
}
/**
* Export submissionTable data as CSV
*
*/
async exportCSV() {
console.log('export csv');
let selected = this.submissionsTable.getSelectedRows().length;
let all = 'selected';
if (selected === 0) {
all = 'active';
}
this.submissionsTable.download('csv', this.activeCourse + '.csv', {}, all);
}
/**
* Get color of a css var
*
* @param {string} cssVar
* @returns {string} color
*/
getColorFromCssVar(cssVar) {
const docStyle = getComputedStyle(this);
let color = docStyle.getPropertyValue(cssVar);
if (color.includes('white')) {
return '#ffffff';
}
if (color.includes('black')) {
return '#000000';
}
return color.trim();
}
/**
* Imports JsPdf,
* Exports submissionTable data as PDF
* Delets JsPdf Plugin
*
*/
async exportPdf() {
let selected = this.submissionsTable.getSelectedRows().length;
let all = 'selected';
if (selected === 0) {
all = 'active';
}
let headerBackground = this.getColorFromCssVar('--dbp-primary-surface');
let headerContent = this.getColorFromCssVar('--dbp-on-primary-surface');
if (!headerBackground || !headerContent) {
headerBackground = '#000000';
headerContent = '#ffffff';
}
window.jspdf = await importJsPDF();
this.submissionsTable.download('pdf', this.activeCourse + '.pdf', {
title: this.activeCourse,
autoTable: { //advanced table styling
theme: 'grid',
styles: {
fontSize: 8
},
headStyles: {
Color: headerContent,
fillColor: headerBackground
},
margin: {top: 60},
pageBreak: 'auto'
}
}, all);
delete window.jspdf;
}
/**
* import xlsx plgin
* Export submissionTable data as Excel
* delete xlsx plugin
*
*/
async exportXLSX() {
console.log('export xlsx');
window.XLSX = await importXLSX();
let selected = this.submissionsTable.getSelectedRows().length;
let all = 'selected';
if (selected === 0) {
all = 'active';
}
this.submissionsTable.download('xlsx', this.activeCourse + '.xlsx', {sheetName: this.activeCourse}, all);
delete window.XLSX;
}
/**
* Function for filtering table
*
*/
filterTable() {
let filter = this._('#searchbar');
let search = this._('#search-select');
let operator = this._('#search-operator');
if (!filter || !search || !operator || !this.submissionsTable)
return;
filter = filter.value;
search = search.value;
operator = operator.value;
if (search !== 'all') {
this.submissionsTable.setFilter(search, operator, filter);
return;
}
let filterArray = [];
this.submissionsColumns.forEach(col => {
filterArray.push({field: col.field, type: operator, value: filter});
});
this.submissionsTable.setFilter([filterArray]);
}
/*
* Clear Filer
*/
clearFilter() {
let filter = this._('#searchbar');
let search = this._('#search-select');
if (!filter || !search || !this.submissionsTable)
return;
filter.value = '';
search.value = 'all';
this.submissionsTable.clearFilter();
}
/**
* Updates the this.submissionColumns Array based on the actual columns of the this.submissionTable
*
*/
updateTableHeaderList() {
if (!this.submissionsTable)
return;
let columns = this.submissionsTable.getColumns();
this.submissionsColumns = [];
columns.forEach((col) => {
let name = col.getDefinition().title;
let field = col.getDefinition().field;
let visibility = col.isVisible();
if (field && !field.includes('no_display') && field !== 'id' && field !== 'id_') {
this.submissionsColumns.push({name: name, field: field, visibility: visibility});
}
});
}
/**
* Creates options for a select box of the t
* his.submissionColumns Array (all possible cols of active table)
*
* @returns {Array<html>} options
*/
getTableHeaderOptions() {
if (!this.submissionsTable)
return;
const i18n = this._i18n;
let options = [];
options[0] = html`
<option value='all'>${i18n.t('show-registrations.all-columns')}</option>`;
this.submissionsColumns.forEach((col, counter) => {
if (!col.visibility) {
options[counter + 1] = html`
<option disabled value='${col.field}'>${col.name}</option>`;
} else {
options[counter + 1] = html`
<option value='${col.field}'>${col.name}</option>`;
}
});
return options;
}
/**
* Opens submission Columns Modal
*
*/
openModal() {
let modal = this._('#submission-modal');
if (modal) {
MicroModal.show(modal, {
disableScroll: true,
disableFocus: false,
});
}
// Scroll list to topdisableScroll: true
let scrollWrapper = this._('#submission-modal-content');
if (scrollWrapper) {
scrollWrapper.scrollTo(0, 0);
}
}
/**
* Close submission Columns Modal
*
*/
closeModal() {
let modal = this._('#submission-modal');
if (modal) {
MicroModal.close(modal);
}
}
/**
* Opens submission detail Modal
*
*/
showDetailedModal() {
let modal = this._('#detailed-submission-modal');
if (modal) {
MicroModal.show(modal, {
disableScroll: true,
disableFocus: false,
});
}
}
/**
* Toggle additional functionalities menu on mobile
*
*/
toggleMoreMenu() {
const menu = this.shadowRoot.querySelector('ul.extended-menu');
const menuStart = this.shadowRoot.querySelector('a.extended-menu-link');
if (menu === null || menuStart === null) {
return;
}
menu.classList.toggle('hidden');
if (!menu.classList.contains('hidden')) {
// add event listener for clicking outside of menu
document.addEventListener('click', this.boundCloseAdditionalMenuHandler);
this.initateOpenAdditionalMenu = true;
} else {
document.removeEventListener('click', this.boundCloseAdditionalMenuHandler);
}
}
/**
* Keydown Event function if enter pressed, then start filtering the table
*
* @param event
*/
pressEnterAndSubmitSearch(event) {
if (event.keyCode === 13) {
const activeElement = this.shadowRoot.activeElement;
if (activeElement && activeElement.id === 'searchbar') {
event.preventDefault();
this.filterTable();
this.hideAdditionalSearchMenu(event);
}
}
}
/**
* Hide additional functionalities menu
* This function is used as bounded event function,
* if clicked outside then we can close the menu
*
*/
hideAdditionalMenu() {
if (this.initateOpenAdditionalMenu) {
this.initateOpenAdditionalMenu = false;
return;
}
const menu = this.shadowRoot.querySelector('ul.extended-menu');
if (menu && !menu.classList.contains('hidden')) this.toggleMoreMenu();
}
/**
* Toggle search menu
*
*/
toggleSearchMenu() {
const menu = this._('#extendable-searchbar .extended-menu');
if (menu === null) {
return;
}
menu.classList.remove('hidden');
if (!menu.classList.contains('hidden')) {
// add event listener for clicking outside of menu
document.addEventListener('click', this.boundCloseAdditionalSearchMenuHandler);
this.initateOpenAdditionalSearchMenu = true;
}
}
/**
* hide search menu
*
* @param e
*/
hideAdditionalSearchMenu(e) {
if (this.initateOpenAdditionalSearchMenu) {
this.initateOpenAdditionalSearchMenu = false;
return;
}
if (e.type !== 'keyup' && e.keyCode !== 13
&& (e.originalTarget && e.originalTarget.parentElement
&& (e.originalTarget.parentElement.classList.contains('extended-menu') ||
e.originalTarget.parentElement.id === 'search-operator' ||
e.originalTarget.parentElement.id === 'search-operator' ||
e.originalTarget.parentElement.id === 'search-select')
|| e.originalTarget && e.originalTarget.id === 'searchbar-menu'
|| e.originalTarget && e.originalTarget.id === 'searchbar')) {
return;
}
const menu = this._('#extendable-searchbar .extended-menu');
if (menu && !menu.classList.contains('hidden')) {
menu.classList.add('hidden');
document.removeEventListener('click', this.boundCloseAdditionalSearchMenuHandler);
}
}
/**
* Toggle visibility of an item
*
* @param {object} item
*/
changeVisibility(item) {
item.visibility = !item.visibility;
if (item.visibility) {
this._('.' + item.field + ' .header-visibility-icon-hide').classList.remove('hidden');
this._('.' + item.field + ' .header-visibility-icon-show').classList.add('hidden');
} else {
this._('.' + item.field + ' .header-visibility-icon-hide').classList.add('hidden');
this._('.' + item.field + ' .header-visibility-icon-show').classList.remove('hidden');
}
}
/**
* Update Submission Table (order and visibility)
*
*/
updateSubmissionTable() {
// Add all known colums in the right order
let newDefs = [];
let addedFields = [];
for (let spec of this.submissionsColumns) {
let col = this.submissionsTable.getColumn(spec.field);
if (!col) {
continue;
}
addedFields.push(spec.field);
newDefs.push(col.getDefinition());
}
// Append everything we didn't know about
for (let col of this.submissionsTable.getColumns()) {
let def = col.getDefinition();
if (addedFields.indexOf(def.field) === -1) {
newDefs.push(def);
addedFields.push(def.field);
}
}
// Replace all columns
this.submissionsTable.setColumns(newDefs);
// Set the visibility status
this.hiddenColumns = false;
for (let spec of this.submissionsColumns) {
let col = this.submissionsTable.getColumn(spec.field);
if (!col) {
continue;
}
if (spec.visibility) {
col.show();
} else {
col.hide();
this.hiddenColumns = true;
}
}
}
/**
* Gets stored submission table settings from localStorage
*
* @returns {boolean} success
*/
getSubmissionTableSettings() {
if (
this.storeSession &&
this.isLoggedIn()
) {
let optionsString = localStorage.getItem('dbp-formalize-tableoptions-' + this.activeCourse + '-' + this.auth['person-id']);
if (!optionsString) {
this.submissionsColumns = [];
return false;
}
try {
let options = JSON.parse(optionsString);
if (options) {
this.submissionsColumns = [...options];
}
} catch (e) {
this.submissionsColumns = [];
console.log(e);
return false;
}
return true;
}
return false;
}
/**
* Stores submission Table settings in localStorage
*
*/
setSubmissionTableSettings() {
if (
this.storeSession &&
this.isLoggedIn()
) {
const publicId = this.auth['person-id'];
localStorage.setItem('dbp-formalize-tableoptions-' + this.activeCourse + '-' + publicId, JSON.stringify(this.submissionsColumns));
}
}
/**
* Moves a header in this.submissionColumns Array and in DOM up
*
* @param {object} i
*/
moveHeaderUp(i) {
let elem = this._('.' + i.field);
let elemIndex = elem.getAttribute('data-index');
if (parseInt(elemIndex) === 0)
return;
let swapElem = this.submissionsColumns.find((col, index) => {
return index + 1 <= this.submissionsColumns.length && this.submissionsColumns[index + 1].field === i.field;
});
this.swapHeader(swapElem, elemIndex, i);
}
/**
* Moves a header in this.submissionColumns Array and in DOM up
*
* @param {object} i
*/
moveHeaderDown(i) {
let elem = this._('.' + i.field);
let elemIndex = elem.getAttribute('data-index');
if (parseInt(elemIndex) === this.submissionsColumns.length - 1)
return;
let swapElem = this.submissionsColumns.find((col, index) => {
return index - 1 >= 0 && this.submissionsColumns[index - 1].field === i.field;
});
this.swapHeader(swapElem, elemIndex, i);
}
/**
* Swaps two elements in this.submissionColumns Array and in DOM
*
* @param {object} swapElem_
* @param {number} elemIndex
* @param {object} i
*/
swapHeader(swapElem_, elemIndex, i) {
let swapElem = this._('.' + swapElem_.field);
let swapElemIndex = swapElem.getAttribute('data-index');
let tmp = this.submissionsColumns[elemIndex];
this.submissionsColumns[elemIndex] = this.submissionsColumns[swapElemIndex];
this.submissionsColumns[swapElemIndex] = tmp;
this.submissionsColumnsUpdated = !this.submissionsColumnsUpdated;
let swapElem2 = this._('.' + swapElem_.field);
function removeClass() {
swapElem2.classList.remove('move-up');
}
function addClass() {
swapElem2.classList.add('move-up');
}
setTimeout(addClass.bind(swapElem2), 0);
setTimeout(removeClass.bind(swapElem2), 400);
}
/**
* Shows last entry of this.submissionTable
*
*/
showLastEntry() {
if (this.currentRow !== null) {
let currentRow = this.currentRow;
let nextIndex = currentRow.getPosition() - 1;
let nextRow;
this.submissionsTable.getRows().forEach((row) => {
if (row.getPosition() === nextIndex) {
nextRow = row;
}
});
if (nextRow) {
this.requestDetailedSubmission(nextRow, nextRow.getData());
}
}
}
/**
* Shows next entry of this.submissionTable
*
*/
showNextEntry() {
if (this.currentRow !== null) {
let currentRow = this.currentRow;
let nextIndex = currentRow.getPosition() + 1;
let nextRow;
this.submissionsTable.getRows().forEach((row) => {
if (row.getPosition() === nextIndex) {
nextRow = row;
console.log('next row:', nextRow);
}
});
if (nextRow) {
this.requestDetailedSubmission(nextRow, nextRow.getData());
}
}
}
static get styles() {
// language=css
return css`
${commonStyles.getThemeCSS()}
${commonStyles.getModalDialogCSS()}
${commonStyles.getRadioAndCheckboxCss()}
${commonStyles.getGeneralCSS(false)}
${fileHandlingStyles.getFileHandlingCss()}
${commonStyles.getNotificationCSS()}
${commonStyles.getActivityCSS()}
${commonStyles.getButtonCSS()}
${tabulatorStyles.getTabulatorStyles()}
.table-wrapper.submissions {
padding-top: 0.5rem;
}
.table-header.submissions {
margin-top: 0.5rem;
}
.btn-row-left {
display: flex;
justify-content: space-between;
gap: 4px;
}
.btn-row-left > * {
display: flex;
align-items: center;
}
.next-btn dbp-icon, .back-btn dbp-icon {
height: 15px;
top: 0px;
}
.next-btn dbp-icon {
margin-left: 0.2em;
margin-right: -0.4em;
}
.back-btn dbp-icon {
margin-left: -0.4em;
margin-right: 0.2em;
}
.actions-buttons {
width: 33px;
position: absolute;
margin: auto;
left: 10px;
}
#detailed-submission-modal-title {
margin-bottom: 10px;
}
#submission-modal-title {
margin-top: unset;
}
#detailed-submission-modal-content {
padding: 0 20px 0px 20px;
}
#detailed-submission-modal-box {
height: auto;
width: auto;
overflow-y: hidden;
min-height: 0;
max-width: 768px;
min-width: 768px;
}
.open-modal-icon {
font-size: 1.3em;