@dbp-topics/sublibrary
Version:
[GitLab Repository](https://github.com/digital-blueprint/sublibrary-app) | [npmjs package](https://www.npmjs.com/package/@dbp-topics/sublibrary) | [Unpkg CDN](https://unpkg.com/browse/@dbp-topics/sublibrary/) | [Sublibrary Bundle](https://gitlab.tugraz.at
530 lines (468 loc) • 19.8 kB
JavaScript
import {createInstance} from './i18n.js';
import {css, html} from 'lit';
import {ScopedElementsMixin} from '@open-wc/scoped-elements';
import {LibraryElement} from './library-element.js';
import * as commonUtils from '@dbp-toolkit/common/utils';
import * as commonStyles from '@dbp-toolkit/common/styles';
import {DataTableView} from '@dbp-toolkit/data-table-view';
import {MiniSpinner} from '@dbp-toolkit/common';
import select2 from 'select2';
import select2LangDe from './i18n/de/select2';
import select2LangEn from './i18n/en/select2';
import select2CSSPath from 'select2/dist/css/select2.min.css';
import $ from 'jquery';
import {classMap} from 'lit/directives/class-map.js';
import {LibrarySelect} from './library-select.js';
select2(window, $);
class LibraryBookList extends ScopedElementsMixin(LibraryElement) {
constructor() {
super();
this._i18n = createInstance();
this.auth = {};
this.lang = this._i18n.language;
this.entryPointUrl = '';
this.personId = '';
this.person = null;
this.books = [];
this.sublibraryIri = '';
this.abortController = null;
this.locationIdentifier = '';
this.locationIdentifiers = [];
this.locationIdentifierSelectId =
'dbp-sublibrary-book-list-location-identifier-select-' + commonUtils.makeId(24);
this.$locationIdentifierSelect = null;
this.inventoryYear = '';
this.inventoryYears = [];
this.inventoryYearSelectId =
'dbp-sublibrary-book-list-inventory-year-select-' + commonUtils.makeId(24);
this.$inventoryYearSelect = null;
let now = new Date();
now.setDate(now.getDate() - 1);
this.analyticsUpdateDate = now.toLocaleDateString(this.lang);
}
static get scopedElements() {
return {
'dbp-library-select': LibrarySelect,
'dbp-data-table-view': DataTableView,
'dbp-mini-spinner': MiniSpinner,
};
}
$(selector) {
return $(this._(selector));
}
/**
* See: https://lit-element.polymer-project.org/guide/properties#conversion-type
*/
static get properties() {
return {
...super.properties,
lang: {type: String},
entryPointUrl: {type: String, attribute: 'entry-point-url'},
sublibraryIri: {type: String, attribute: 'sublibrary-iri', reflect: true},
books: {type: Object, attribute: false},
locationIdentifiers: {type: Array, attribute: false},
locationIdentifier: {type: String, attribute: false},
inventoryYears: {type: Array, attribute: false},
inventoryYear: {type: String, attribute: false},
analyticsUpdateDate: {type: Object, attribute: false},
auth: {type: Object},
};
}
loginCallback() {
super.loginCallback();
this.loadTable();
}
connectedCallback() {
super.connectedCallback();
this.updateComplete.then(() => {
this.initLocationIdentifierSelect();
this.initInventoryYearSelect();
// language=css
const css = `
table.dataTable tbody tr.odd {
background-color: var(--dbp-background);
}
`;
this._(this.getScopedTagName('dbp-data-table-view')).setCSSStyle(css);
this.loadTable();
});
}
update(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
switch (propName) {
case 'lang':
this._i18n.changeLanguage(this.lang);
this.updateLocationIdentifierSelect();
// we need to update the column titles
this.buildTable(false);
break;
case 'sublibraryIri':
this.loadTable();
break;
case 'locationIdentifiers':
this.updateLocationIdentifierSelect();
break;
case 'locationIdentifier':
case 'inventoryYear':
this.buildTable(false);
break;
case 'inventoryYears':
this.updateInventoryYearSelect();
break;
}
});
super.update(changedProperties);
}
updateLocationIdentifierSelect() {
this.initLocationIdentifierSelect();
// if (this.$locationIdentifierSelect !== null) {
// this.$locationIdentifierSelect.trigger('change.select2');
// }
}
updateInventoryYearSelect() {
this.initInventoryYearSelect();
}
disconnectedCallback() {
if (this.abortController !== null) {
this.abortController.abort();
}
super.disconnectedCallback();
}
loadTable() {
const that = this;
const $bookListBlock = that.$('#book-list-block');
const $noBooksBlock = that.$('#no-books-block');
$bookListBlock.hide();
$noBooksBlock.hide();
if (!this.isLoggedIn()) return;
if (this.sublibraryIri === '') {
return;
}
const parts = this.sublibraryIri.split('/');
const sublibraryIdentifier = parts[parts.length - 1];
const apiUrl = this.entryPointUrl + '/sublibrary/book-offers?perPage=9999999&sublibrary=' + sublibraryIdentifier;
const $booksLoadingIndicator = that.$('#books-loading');
$booksLoadingIndicator.show();
// abort previous list fetch if it is still running
if (this.abortController !== null) {
this.abortController.abort();
}
this.abortController = new AbortController();
const signal = this.abortController.signal;
// load list of books for organization
fetch(apiUrl, {
headers: {
'Content-Type': 'application/ld+json',
Authorization: 'Bearer ' + this.auth.token,
},
signal: signal,
})
.then((result) => {
if (!result.ok) throw result;
if (result.headers.has('x-analytics-update-date')) {
const date = new Date(result.headers.get('x-analytics-update-date'));
this.analyticsUpdateDate =
date.toLocaleDateString(this.lang) +
' ' +
date.toLocaleTimeString(this.lang);
}
return result.json();
})
.then((result) => {
that.books = result['hydra:member'];
that.buildTable();
$booksLoadingIndicator.hide();
})
.catch((error) => {
that.handleFetchError(error, that._i18n.t('book-list.error-load-books'));
if(this.abortController === null)
$booksLoadingIndicator.hide();
});
}
buildTable(updateFilterSelects = true) {
const that = this;
const $bookListBlock = this.$('#book-list-block');
const $noBooksBlock = this.$('#no-books-block');
let locationIdentifiers = [];
let inventoryYears = [];
if (this.books.length > 0) {
const vdtv1 = this._('#book-books-1');
if (vdtv1 !== null) {
const columns = [
{title: this._i18n.t('book-list.book-title')},
{title: this._i18n.t('book-list.book-author')},
{title: this._i18n.t('book-list.book-publication-year')},
{title: this._i18n.t('book-list.book-publisher')},
{title: this._i18n.t('book-list.book-availability-date')},
null,
{title: this._i18n.t('book-list.book-barcode')},
{title: this._i18n.t('book-list.book-location-identifier')},
{title: this._i18n.t('book-list.book-description')},
];
// sorting will be done by hidden columns
const columnDefs = [
{targets: [4], orderData: [5]},
{targets: [5], visible: false},
];
const tbl = [];
this.books.forEach(function (bookOffer) {
const availabilityStarts = new Date(bookOffer.availabilityStarts);
const inventoryYear =
bookOffer.availabilityStarts !== null
? availabilityStarts.getFullYear().toString()
: '';
if (
(that.locationIdentifier === '' ||
that.locationIdentifier === bookOffer.locationIdentifier) &&
(that.inventoryYear === '' || that.inventoryYear === inventoryYear)
) {
const datePublished = new Date(bookOffer.book.datePublished);
const row = [
bookOffer.book.title,
bookOffer.book.author,
bookOffer.book.datePublished !== null
? datePublished.getFullYear()
: '',
bookOffer.book.publisher,
bookOffer.availabilityStarts !== null
? availabilityStarts.toLocaleDateString('de-AT')
: '',
bookOffer.availabilityStarts,
bookOffer.barcode,
bookOffer.locationIdentifier,
bookOffer.description,
];
tbl.push(row);
}
if (updateFilterSelects) {
if (
bookOffer.locationIdentifier !== '' &&
!locationIdentifiers.includes(bookOffer.locationIdentifier)
) {
locationIdentifiers.push(bookOffer.locationIdentifier);
}
if (inventoryYear !== '' && !inventoryYears.includes(inventoryYear)) {
inventoryYears.push(inventoryYear);
}
}
});
vdtv1.set_columns(columns).set_columnDefs(columnDefs).set_datatable(tbl);
}
$bookListBlock.show();
} else {
$noBooksBlock.show();
}
if (updateFilterSelects) {
this.locationIdentifiers = locationIdentifiers.sort();
this.locationIdentifier = '';
if (this.$locationIdentifierSelect !== null) {
this.$locationIdentifierSelect.val('');
}
this.inventoryYears = inventoryYears.sort().reverse();
this.inventoryYear = '';
if (this.$inventoryYearSelect !== null) {
this.$inventoryYearSelect.val('');
}
}
}
onLanguageChanged(e) {
this.lang = e.detail.lang;
}
locationIdentifierSelect2IsInitialized() {
return (
this.$locationIdentifierSelect !== null &&
this.$locationIdentifierSelect.hasClass('select2-hidden-accessible')
);
}
/**
* Initializes the locationIdentifier Select2 selector
*/
initLocationIdentifierSelect() {
let that = this;
this.$locationIdentifierSelect = this.$('#' + this.locationIdentifierSelectId);
// destroy previous instance of Select2
if (this.locationIdentifierSelect2IsInitialized()) {
this.$locationIdentifierSelect.select2('destroy');
}
this.$locationIdentifierSelect
.select2({
width: '100%',
allowClear: true,
language: this.lang === 'de' ? select2LangDe() : select2LangEn(),
placeholder: this._i18n.t('book-list.location-identifier-select-placeholder'),
dropdownParent: this.$('#location-identifier-select-dropdown'),
})
.on('select2:select', function (e) {
that.locationIdentifier = e.params.data.id;
})
.on('select2:clear', function () {
that.locationIdentifier = '';
})
.on('select2:open', function () {
// close the selector when clicked outside of it
that.$('#location-identifier-select-dropdown .select2-search__field').blur(() => {
// the delay is a workaround to prevent troubles
setTimeout(() => {
that.$locationIdentifierSelect.select2('close');
}, 250);
});
//
});
}
inventoryYearSelect2IsInitialized() {
return (
this.$inventoryYearSelect !== null &&
this.$inventoryYearSelect.hasClass('select2-hidden-accessible')
);
}
/**
* Initializes the inventory year Select2 selector
*/
initInventoryYearSelect() {
let that = this;
this.$inventoryYearSelect = this.$('#' + this.inventoryYearSelectId);
// destroy previous instance of Select2
if (this.inventoryYearSelect2IsInitialized()) {
this.$inventoryYearSelect.select2('destroy');
}
this.$inventoryYearSelect
.select2({
width: '100%',
allowClear: true,
language: this.lang === 'de' ? select2LangDe() : select2LangEn(),
placeholder: this._i18n.t('book-list.inventory-year-select-placeholder'),
dropdownParent: this.$('#inventory-year-select-dropdown'),
})
.on('select2:select', function (e) {
that.inventoryYear = e.params.data.id;
})
.on('select2:clear', function () {
that.inventoryYear = '';
})
.on('select2:open', function () {
// close the selector when clicked outside of it
that.$('#inventory-year-select-dropdown .select2-search__field').blur(() => {
// the delay is a workaround to prevent troubles
setTimeout(() => {
that.$inventoryYearSelect.select2('close');
}, 250);
});
//
});
}
static get styles() {
// language=css
return css`
${commonStyles.getThemeCSS()}
${commonStyles.getGeneralCSS()}
${commonStyles.getNotificationCSS()}
${commonStyles.getSelect2CSS()}
.hidden {
display: none;
}
#book-list-block,
#no-books-block {
display: none;
}
form,
table {
width: 100%;
}
#no-books-block {
font-weight: bold;
}
`;
}
onSublibraryChanged(e) {
this.sublibraryIri = e.detail.value;
}
render() {
let locationIdentifierItemTemplates = [];
this.locationIdentifiers.forEach((item) => {
locationIdentifierItemTemplates.push(html`<option value="${item}">${item}</option>`);
});
let inventoryYearItemTemplates = [];
this.inventoryYears.forEach((item) => {
inventoryYearItemTemplates.push(html`<option value="${item}">${item}</option>`);
});
const select2CSS = commonUtils.getAssetURL(select2CSSPath);
const i18n = this._i18n;
return html`
<link rel="stylesheet" href="${select2CSS}" />
<form
class="${classMap({
hidden: !this.isLoggedIn() || !this.hasLibraryPermissions() || this.isLoading(),
})}">
<div class="field">
${i18n.t('book-list.current-state')}: ${this.analyticsUpdateDate}
</div>
<div class="field">
<label class="label">${i18n.t('organization-select.label')}</label>
<div class="control">
<dbp-library-select
subscribe="lang:lang,entry-point-url:entry-point-url,auth:auth"
value="${this.sublibraryIri}"
="${this.onSublibraryChanged}"></dbp-library-select>
</div>
</div>
<dbp-mini-spinner
id="books-loading"
text="${i18n.t('book-list.mini-spinner-text')}"
style="font-size: 2em; display: none;"></dbp-mini-spinner>
<div id="book-list-block">
<div class="field">
<label class="label">${i18n.t('book-list.book-location-identifier')}</label>
<div class="control">
<select id="${this.locationIdentifierSelectId}">
<option value=""></option>
${locationIdentifierItemTemplates}
</select>
<div id="location-identifier-select-dropdown"></div>
</div>
</div>
<div class="field">
<label class="label">${i18n.t('book-list.book-inventory-year')}</label>
<div class="control">
<select id="${this.inventoryYearSelectId}">
<option value=""></option>
${inventoryYearItemTemplates}
</select>
<div id="inventory-year-select-dropdown"></div>
</div>
</div>
<div class="field">
<label class="label">${i18n.t('book-list.books')}</label>
<div class="control">
<dbp-data-table-view
searching
paging
exportable
export-name="${i18n.t('book-list.export-name', {
organizationCode: this.getOrganizationCode(),
})}"
subscribe="lang:lang"
id="book-books-1"></dbp-data-table-view>
</div>
</div>
</div>
<div id="no-books-block">${i18n.t('book-list.no-books')}</div>
</form>
<div
class="notification is-warning ${classMap({
hidden: this.isLoggedIn() || this.isLoading(),
})}">
${i18n.t('error-login-message')}
</div>
<div
class="notification is-danger ${classMap({
hidden: this.hasLibraryPermissions() || !this.isLoggedIn() || this.isLoading(),
})}">
${i18n.t('error-permission-message')}
</div>
<div class="${classMap({hidden: !this.isLoading()})}">
<dbp-mini-spinner></dbp-mini-spinner>
</div>
`;
}
}
commonUtils.defineCustomElement('dbp-sublibrary-book-list', LibraryBookList);