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 {css, 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 * as commonStyles from 'vpu-common/styles'; import select2CSSPath from 'select2/dist/css/select2.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; this.isSearching = false; this.lastResult = {}; } 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(() => { if (this.select2IsInitialized()) { that.$select.select2('close'); } }, 500); }); // try an init when user-interface is loaded that.initJSONLD(); }); } initJSONLD() { const that = this; JSONLD.initialize(this.entryPointUrl, function (jsonld) { that.jsonld = jsonld; that.active = true; // we need to poll because maybe the user interface isn't loaded yet // Note: we need to call initSelect2() in a different function so we can access "this" inside initSelect2() commonUtils.pollFunc(() => { return that.initSelect2(); }, 10000, 100); }, {}, this.lang); } /** * Initializes the Select2 selector */ initSelect2(ignorePreset = false) { const that = this; const $this = $(this); if (this.jsonld === null) { return false; } // 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 === null) { return false; } // we need to destroy Select2 and remove the event listeners before we can initialize it again if (this.$select && this.$select.hasClass('select2-hidden-accessible')) { this.$select.select2('destroy'); this.$select.off('select2:select'); this.$select.off('select2:closing'); } 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: 500, url: apiUrl, contentType: "application/ld+json", beforeSend: function (jqXHR) { jqXHR.setRequestHeader('Authorization', 'Bearer ' + window.VPUAuthToken); that.isSearching = true; }, data: function (params) { return { search: params.term.trim(), 'library-only': 1 }; }, processResults: function (data) { console.log(data); that.lastResult = data; const results = that.jsonld.transformMembers(data, localContext); console.log("results"); console.log(results); return { results: results }; }, error: errorUtils.handleXhrError, complete: (jqXHR, textStatus) => { that.isSearching = false; } } }).on("select2:select", function (e) { // set custom element attributes const identifier = e.params.data.id; const object = findObjectInApiResults(identifier, that.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 })); } }).on("select2:closing", (e) => { if (that.isSearching) { e.preventDefault(); } }); // TODO: doesn't work here // this.$('.select2-selection__arrow').click(() => { // console.log("click"); // }); // 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 true; } update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { case "lang": i18n.changeLanguage(this.lang); if (this.select2IsInitialized()) { // no other way to set an other language at runtime did work this.initSelect2(true); } break; case "value": if (!this.ignoreValueUpdate && this.select2IsInitialized()) { this.initSelect2(); } this.ignoreValueUpdate = false; break; case "entryPointUrl": this.initJSONLD(); break; } }); super.update(changedProperties); } select2IsInitialized() { return this.$select !== null && this.$select.hasClass("select2-hidden-accessible"); } static get styles() { // language=css return css` ${commonStyles.getThemeCSS()} ${commonStyles.getGeneralCSS()} .select2-dropdown { border-radius: var(--vpu-border-radius); } .select2-container--default .select2-selection--single { border-radius: var(--vpu-border-radius); } .select2-container--default .select2-selection--single .select2-selection__rendered { color: inherit; } `; } render() { commonUtils.initAssetBaseURL('vpu-person-select-src'); const select2CSS = commonUtils.getAssetURL(select2CSSPath); return html` <link rel="stylesheet" href="${select2CSS}"> <style> #${this.selectId} { width: 100%; } </style> <div class="select"> <!-- 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> </div> `; } } commonUtils.defineCustomElement('vpu-person-select', PersonSelect);