PageSourceSearch

https://www.kh-schloss-werneck.de/_/scripts/rgElements/src/Elements/rgSelectcontent/rg-selectcontent.js

js kh-schloss-werneck.de collected 2026-10-04 19:49:38 UTC 11,433 bytes, 295 lines download raw bytes

1import {rgElement} from '../rgElement/rg-element.js'
2export class rgSelectcontent extends rgElement {
3
4    $element = null;
5    $hiddenelement = null;
6    $listelement = null;
7    #trclass = null;
8    #rootnode = null;
9    #fetching = false;
10    #timer = null;
11    #oldValue = {
12        value: '',
13        displayText: ''
14    };
15    #start = 0;
16    #limit = 10;
17    #listElementClick = false;
18
19    constructor() {
20        super();
21    }
22
23    connectedCallback() {
24        this.setUpElement();
25        !this.shadowRoot && this.attachShadow({mode: 'open'});
26        this.style.display = 'block';
27
28        this.#trclass = this.dataset.trtype;
29        this.#rootnode = this.dataset.root;
30        /*if (this.form && this.dataset.name) {
31            this.$element = this.form.querySelector('*[name="' + this.dataset.name + '"]');
32        } else if (this.dataset.name) {
33            this.$element = document.querySelector('*[name="' + this.dataset.name + '"]');
34        }*/
35        if (!this.$element) {
36            let input = document.createElement('input');
37            input.setAttribute('type', 'text');
38            input.setAttribute('value', this.dataset.displayvalue);
39            input.setAttribute('name', 'livesearch' + this.dataset.name);
40            this.$element = this.shadowRoot.host.parentElement.insertBefore(input, this.shadowRoot.host);
41        }
42        const linkElem = document.createElement('link');
43        linkElem.setAttribute('rel', 'stylesheet');
44        linkElem.setAttribute('href', this.rootpath + '/css/rg-selectcontent.css');
45        let hiddeninput = document.createElement('input');
46        hiddeninput.setAttribute('type', 'hidden');
47        hiddeninput.setAttribute('name', this.dataset.name);
48        hiddeninput.setAttribute('value', this.dataset.value);
49        this.$hiddenelement = this.shadowRoot.host.parentElement.insertBefore(hiddeninput, this.shadowRoot.host);
50
51        const adoptedCSSTag = document.createElement('style');
52        adoptedCSSTag.innerHTML = this.copyStyles('.selectcontent');
53        //append them
54        this.shadowRoot.append(linkElem, adoptedCSSTag);
55        this.$element.addEventListener('keydown', (ev) => {
56            if([
57                'Enter',
58                'NumpadEnter',
59                'ArrowUp',
60                'ArrowDown'
61            ].includes(ev.code)) {
62                ev.preventDefault();
63                return false;
64            }
65        });
66        this.$element.addEventListener('keyup', this.#handleKey.bind(this));
67        this.$element.addEventListener('click', function (ev) {
68            if (this.$listelement && this.$listelement.hasChildNodes()) {
69                this.$listelement.style.display = 'block';
70            }
71        }.bind(this));
72        this.#oldValue.displayText = this.$element.value;
73        this.#oldValue.value = this.$hiddenelement.value;
74        this.$element.addEventListener('blur', function (ev) {
75            if(this.#listElementClick) {
76                return;
77            }
78            if (this.$listelement) {
79                this.$listelement.style.display = 'none';
80            }
81            if (this.$hiddenelement.value === '') {
82                this.$element.value = this.#oldValue.displayText;
83                this.$hiddenelement.value = this.#oldValue.value;
84            }
85        }.bind(this));
86        if (typeof recon === 'object') {
87            recon.on('categorySelect', function (config) {
88                if (config.contentroot && config.contentroot[this.$hiddenelement.name]) {
89                    //Evtl. per attribute data-root???
90                    this.#rootnode = config.contentroot[this.$hiddenelement.name];
91                    /*const event = new KeyboardEvent('keyup', {
92                        bubbles: true,
93                        cancelable: true
94                    });
95                    this.#showLoadingResults();
96                    this.$element.dispatchEvent(event);*/
97                }
98            }.bind(this));
99        }
100
101        this.setupComplete();
102    }
103
104    static get observedAttributes() {
105        return ['data-value', 'data-displayvalue', 'data-trtype'];
106    }
107
108
109    attributeChangedCallback(name, oldValue, newValue) {
110        if (this.$element) {
111            debugger;
112        }
113    }
114
115    #getUrl() {
116        let newValue = this.$element.value.trim(),
117            nodeFilter = this.#rootnode ? '&r=' + this.#rootnode : '',
118            match = newValue.match(/(^\d+)\s+/);
119        if (match) {
120            newValue = match[1];
121        }
122        return `livesearch.js?_func=fndCnt&trcl=${this.#trclass}&viewmode=list&_trid=-1&start=${this.#start}&limit=${this.#limit}&filter=${newValue}${nodeFilter}`;
123    }
124
125
126    #handleKey(ev) {
127        switch (ev.key) {
128            case 'Escape':
129                if (this.$listelement) {
130                    this.$listelement.style.display = 'none';
131                }
132                break;
133            case 'Enter':
134            case 'NumpadEnter':
135                if (this.$listelement && this.$listelement.style.display === 'block') {
136                    let activeListElement = this.$listelement.querySelector('.active');
137                    if (activeListElement) {
138                        let event = new MouseEvent('pointerdown', {
139                            bubbles: true,
140                            cancelable: true
141                        });
142                        activeListElement.dispatchEvent(event);
143                    }
144                }
145                break;
146            case 'ArrowLeft':
147            case 'ArrowRight':
148                break;
149            case 'ArrowDown':
150            case 'ArrowUp':
151                if (this.$listelement) {
152                    this.$listelement.style.display = 'block';
153                    let activeListElement = this.$listelement.querySelector('.active'),
154                        nextElementToSelect,
155                        event = new MouseEvent('mouseover', {
156                            bubbles: true,
157                            cancelable: true
158                        });
159                    if (activeListElement) {
160                        activeListElement.classList.remove('active');
161                        if (ev.key === 'ArrowDown') {
162                            nextElementToSelect = activeListElement.nextElementSibling || activeListElement;
163                        } else {
164                            nextElementToSelect = activeListElement.previousElementSibling || activeListElement;
165                        }
166                        nextElementToSelect.dispatchEvent(event);
167                    } else {
168                        this.$listelement.firstChild.dispatchEvent(event);
169                    }
170                }
171                break;
172            default:
173                this.$hiddenelement.value = '';
174                this.#start = 0;
175                let newValue = this.$element.value.trim();
176                if (!this.#fetching && newValue.length >= 3) {
177                    if (this.#timer) {
178                        clearTimeout(this.#timer);
179                    }
180                    this.#timer = setTimeout(function () {
181                        this.#fetch();
182                    }.bind(this), 500);
183                }
184                break;
185        }
186    }
187
188    #fetch() {
189        this.#fetching = true;
190        this.#showLoadingResults();
191        fetch(this.#getUrl(), {
192            method: 'GET',
193            mode: 'same-origin',
194            cache: 'no-cache',
195            headers: {
196                'X-Requested-With': 'XMLHttpRequest'
197            },
198            redirect: 'follow'
199        }).then((response) => response.json()).then(function (data) {
200            this.#fetching = false;
201            this.#showResluts(data);
202            this.#listElementClick = false;
203        }.bind(this)).catch( (ex) => {
204            console.error(ex);
205        } )
206    }
207
208    #createListElement() {
209        if (!this.$listelement) {
210            this.$listelement = document.createElement('div');
211            this.$listelement.classList.add('rg-selectcontent');
212            this.shadowRoot.append(this.$listelement);
213            let bounds = this.$element.getBoundingClientRect();
214            this.$listelement.style.minWidth = bounds.width + 'px';
215        }
216    }
217
218    #showLoadingResults() {
219        this.#clearResults();
220        let loadingDiv = document.createElement('div');
221        loadingDiv.classList.add('rg-selectcontent__loading');
222        loadingDiv.innerHTML = '<div></div><div></div><div></div><div></div>';
223        this.$listelement.append(loadingDiv);
224    }
225
226    #clearResults() {
227        this.#createListElement();
228        let childNode = this.$listelement.firstChild;
229        while (childNode) {
230            this.$listelement.removeChild(childNode);
231            childNode = this.$listelement.firstChild
232        }
233    }
234
235    #showResluts(data) {
236        this.#createListElement();
237        this.#clearResults();
238        for (const [key, value] of Object.entries(data.contents)) {
239            let entry = document.createElement('div');
240            entry.classList.add('rg-selectcontent__listelement');
241            entry.innerHTML = value.title;
242            entry.setAttribute('data-id', value.id);
243            entry.setAttribute('data-title', value.title);
244            this.$listelement.append(entry);
245            entry.addEventListener('pointerdown', function (ev) {
246                this.$hiddenelement.value = ev.target.dataset.id;
247                this.$element.value = ev.target.dataset.title;
248                this.#oldValue.value = ev.target.dataset.id;
249                this.#oldValue.displayText = ev.target.dataset.title;
250                this.$listelement.style.display = 'none';
251            }.bind(this));
252            entry.addEventListener('mouseover', function (ev) {
253                this.classList.add('active');
254            });
255            entry.addEventListener('mouseout', function (ev) {
256                this.classList.remove('active');
257            });
258        }
259        let totalCount = Number(data.totalCount);
260        if (totalCount === 0) {
261            this.$listelement.style.display = 'none';
262            return;
263        }
264        if (totalCount > 10) {
265            let pager = document.createElement('div'),
266                arrowLeft = document.createElement('div'),
267                arrowRight = document.createElement('div');
268            arrowLeft.innerHTML = '&lt;&lt;';
269            arrowRight.innerHTML = '&gt;&gt;';
270            if (this.#start === 0) {
271                arrowLeft.classList.add('hidden');
272            }
273            if (this.#start + this.#limit >= totalCount) {
274                arrowRight.classList.add('hidden');
275            }
276            arrowLeft.addEventListener('pointerdown', function (ev) {
277                this.#listElementClick = true;
278                this.#start -= this.#limit;
279                if (this.#start < 0) {
280                    this.#start = 0;
281                }
282                this.#fetch();
283            }.bind(this));
284            arrowRight.addEventListener('pointerdown', function (ev) {
285                this.#listElementClick = true;
286                this.#start += this.#limit;
287                this.#fetch();
288            }.bind(this));
289            pager.append(arrowLeft, arrowRight);
290            pager.classList.add('rg-selectcontent__pager')
291            this.$listelement.append(pager);
292        }
293        this.$listelement.style.display = 'block';
294    }
295}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.