-
Reiter, Christoph authoredReiter, Christoph authored
vpu-person-select.js 7.86 KiB
import $ from 'jquery';
import {findObjectInApiResults} from './utils.js';
import select2 from 'select2';
import select2LangDe from './i18n/de/select2'
import select2LangEn from './i18n/en/select2'
import JSONLD from 'vpu-common/jsonld';
import {html} from 'lit-element';
import {i18n} from './i18n.js';
import VPULitElementJQuery from 'vpu-common/vpu-lit-element-jquery';
import * as commonUtils from 'vpu-common/utils';
import select2CSSPath from 'select2/dist/css/select2.min.css';
import bulmaCSSPath from "bulma/css/bulma.min.css";
import * as errorUtils from "vpu-common/error";
select2(window, $);
class PersonSelect extends VPULitElementJQuery {
constructor() {
super();
this.lang = 'de';
this.entryPointUrl = commonUtils.getAPiUrl();
this.jsonld = null;
this.$select = null;
this.active = false;
// For some reason using the same ID on the whole page twice breaks select2 (regardless if they are in different custom elements)
this.selectId = 'person-select-' + commonUtils.makeId(24);
this.value = '';
this.ignoreValueUpdate = false;
}
static get properties() {
return {
lang: { type: String },
active: { type: Boolean, attribute: false },
entryPointUrl: { type: String, attribute: 'entry-point-url' },
value: { type: String },
};
}
clear() {
this.$select.val(null).trigger('change').trigger('select2:unselect');
}
connectedCallback() {
super.connectedCallback();
const that = this;
this.updateComplete.then(()=>{
that.$select = that.$('#' + that.selectId);
// close the selector on blur of the web component
$(that).blur(() => {
// the 500ms delay is a workaround to actually get an item selected when clicking on it,
// because the blur gets also fired when clicking in the selector
setTimeout(() => {that.$select.select2('close')}, 500);
});
});
}
/**
* Initializes the Select2 selector
*/
initSelect2(ignorePreset = false) {
const that = this;
const $this = $(this);
let lastResult = {};
// find the correct api url for a person
const apiUrl = this.jsonld.getApiUrlForIdentifier("http://schema.org/Person");
// const apiUrl = this.jsonld.getApiUrlForEntityName("Event");
// the mapping we need for Select2
const localContext = {
"id": "@id",
"text": "http://schema.org/name"
};
if (this.$select.hasClass('select2-hidden-accessible')) {
this.$select.select2('destroy');
}
this.$select.select2({
width: '100%',
language: this.lang === "de" ? select2LangDe() : select2LangEn(),
minimumInputLength: 2,
placeholder: i18n.t('person-select.placeholder'),
dropdownParent: this.$('#person-select-dropdown'),
ajax: {
delay: 250,
url: apiUrl,
contentType: "application/ld+json",
beforeSend: function (jqXHR) {
jqXHR.setRequestHeader('Authorization', 'Bearer ' + window.VPUAuthToken);
},
data: function (params) {
return {
search: params.term.trim(),
'library-only': 1
};
},
processResults: function (data) {
console.log(data);
lastResult = data;
const results = that.jsonld.transformMembers(data, localContext);
console.log("results");
console.log(results);
return {
results: results
};
},
error: errorUtils.handleXhrError
}
}).on("select2:select", function (e) {
// set custom element attributes
const identifier = e.params.data.id;
const object = findObjectInApiResults(identifier, lastResult);
$this.attr("data-object", JSON.stringify(object));
$this.data("object", object);
if ($this.attr("value") !== identifier) {
that.ignoreValueUpdate = true;
$this.attr("value", identifier);
// fire a change event
that.dispatchEvent(new CustomEvent('change', {
detail: {
value: identifier,
},
bubbles: true
}));
}
});
// preset a person
if (!ignorePreset && this.value !== '') {
const apiUrl = this.entryPointUrl + this.value;
fetch(apiUrl, {
headers: {
'Content-Type': 'application/ld+json',
'Authorization': 'Bearer ' + window.VPUAuthToken,
},
})
.then(result => {
if (!result.ok) throw result;
return result.json();
})
.then((person) => {
const identifier = person["@id"];
const option = new Option(person.name, identifier, true, true);
$this.attr("data-object", JSON.stringify(person));
$this.data("object", person);
that.$select.append(option).trigger('change');
// fire a change event
that.dispatchEvent(new CustomEvent('change', {
detail: {
value: identifier,
},
bubbles: true
}));
}).catch(() => {});
}
return this.$select;
}
update(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
switch (propName) {
case "lang":
i18n.changeLanguage(this.lang);
if (this.$select !== null && this.$select.hasClass("select2-hidden-accessible")) {
// no other way to set an other language at runtime did work
this.initSelect2(true);
}
break;
case "value":
if (!this.ignoreValueUpdate && this.$select !== null && this.$select.hasClass("select2-hidden-accessible")) {
this.initSelect2();
}
this.ignoreValueUpdate = false;
break;
case "entryPointUrl":
const that = this;
JSONLD.initialize(this.entryPointUrl, function (jsonld) {
that.jsonld = jsonld;
that.active = true;
that.$select = that.initSelect2();
}, {}, that.lang);
break;
}
});
super.update(changedProperties);
}
render() {
commonUtils.initAssetBaseURL('vpu-person-select-src');
const select2CSS = commonUtils.getAssetURL(select2CSSPath);
const bulmaCSS = commonUtils.getAssetURL(bulmaCSSPath);
return html`
<link rel="stylesheet" href="${bulmaCSS}">
<link rel="stylesheet" href="${select2CSS}">
<style>
#${this.selectId} {
width: 100%;
}
</style>
<!-- https://select2.org-->
<select id="${this.selectId}" name="person" class="select" ?disabled=${!this.active}>${!this.active ? html`<option value="" disabled selected>${ i18n.t('person-select.login-required')}</option>` : ''}</select>
<div id="person-select-dropdown"></div>
`;
}
}
commonUtils.defineCustomElement('vpu-person-select', PersonSelect);