PageSourceSearch

https://www.klagenfurt.at/_assets/3aac61a435988e1bf9abea60ea0f7ca7…/Dist/atomic-modal.js?1782816998

js klagenfurt.at collected 2026-10-02 03:42:21 UTC 11,032 bytes, 336 lines download raw bytes

1class AtomicDropdown extends HTMLElement {
2    constructor() {
3        super();
4        this.attachShadow({mode: "open"});
5        this.setAttribute("closed","");
6    }
7
8    get clickElement(){
9        return this.querySelector("[slot='click-element']");
10    }
11
12    get animation(){
13        return this.getAttribute("animation");
14    }
15
16    openDropdown(){
17        if(this.isOpen){
18            return;
19        }else{
20            this.removeAttribute("closed");
21            this.removeAttribute("closing");
22            this.setAttribute("opening","");
23        }
24    }
25
26    closeDropdown(e){
27        // prevend bubble up events to close dropdown
28        if(e){
29            let related = e.relatedTarget;
30
31            while (related && related !== this && related !== document) {
32                related = related.parentNode;
33            }
34            if (related === this) {
35                return;
36            }
37        }
38
39        if(this.isClosed){
40            return;
41        }
42        this.removeAttribute("opened");
43        this.removeAttribute("opening");
44        this.setAttribute("closing","");
45    }
46
47    get group(){
48        return this.getAttribute("group");
49    }
50
51    get isOpenedByHover(){
52        return this.hasAttribute("openOnHover");
53    }
54
55    get isOpen(){
56        return this.hasAttribute("opened");
57    }
58
59    get isClosed(){
60        return this.hasAttribute("closed");
61    }
62
63    get getLinkInClickElement(){
64        return this.clickElement.querySelector("a");
65    }
66
67    get slideContent(){
68        return this.shadowRoot.querySelector(".slide-content");
69    }
70
71    connectedCallback() {
72        this.render();
73        this._setClickEvent();
74        this._setHoverEvent();
75        this._setTransitionEvents();
76
77        const closeModalBtn = this.shadowRoot.querySelector('#close-modal-btn');
78
79        closeModalBtn.addEventListener('click', (e) => {
80            e.stopPropagation();
81            this.closeDropdown();
82        });
83    }
84
85    disconnectedCallback() {
86        // this.clickElement.removeEventListener('click', this.handleClickElementClick);
87        // this.slideContent.removeEventListener('transitionend', this.handleTransitionEnd);
88    }
89
90    handleClickElementClick(event){
91        this.disableDefaultClickBehaviour();
92        event.stopPropagation();
93        if(this.isOpen){
94            this.closeDropdown(event);
95            document.removeEventListener('click', this.boundHandleClickOutside);
96        } else {
97            this.openDropdown();
98            this.boundHandleClickOutside = this.handleClickOutside.bind(this);
99            setTimeout(() => { // Dies stellt sicher, dass der Listener nicht sofort ausgelöst wird
100                document.addEventListener('click', this.boundHandleClickOutside, false);
101            }, 0);
102        }
103        if(this.group){
104            this.closeGroupMembers();
105        }
106    };
107
108    handleClickOutside(event){
109        if (this.contains(event.target) === false) {
110            this.closeDropdown(event);
111            document.removeEventListener('click', this.boundHandleClickOutside);
112        }
113    };
114
115    handleTransitionEnd(){
116        if(this.hasAttribute("opening")){
117            this.removeAttribute("opening");
118            this.removeAttribute("closing");
119            this.setAttribute("opened","");
120        } else if(this.hasAttribute("closing")){
121            this.removeAttribute("closing");
122            this.removeAttribute("opening");
123            this.setAttribute("closed","");
124        }
125    };
126
127    disableDefaultClickBehaviour(){
128        if(this.clickElement.tagName === "A"){
129            this.clickElement.addEventListener('click', (e) => {
130                e.preventDefault();
131                e.stopPropagation();
132            });
133        }
134        if(!this.getLinkInClickElement) return;
135        this.getLinkInClickElement.style.pointerEvents = "none";
136        this.getLinkInClickElement.addEventListener('click', (e) => {
137            e.preventDefault();
138            e.stopPropagation();
139        });
140    }
141
142    closeGroupMembers(){
143        if(!this.group) return;
144        const members = document.querySelectorAll(`atomic-dropdown[group="${this.group}"]`);
145        if(members.length === 0) return;
146        members.forEach((member)=>{
147            if(member !== this){
148                member.closeDropdown();
149            }
150        })
151    };
152
153    _setClickEvent(){
154        if(this.isOpenedByHover) return;
155        this.disableDefaultClickBehaviour.bind(this)();
156        this.clickElement.addEventListener('click', this.handleClickElementClick.bind(this), false);
157    }
158
159    _setTransitionEvents(){
160        this.slideContent.addEventListener('transitionend', this.handleTransitionEnd.bind(this));
161    }
162
163    _setHoverEvent() {
164        if(!this.isOpenedByHover) return;
165        this.addEventListener('mouseover', this.openDropdown.bind(this));
166        this.addEventListener('mouseout', this.closeDropdown.bind(this));
167    }
168
169    _activateClickOutside(){
170        document.addEventListener('click', this.handleClickOutside.bind(this), false);
171    }
172
173    render() {
174        this.shadowRoot.innerHTML = `
175            <style>
176                :host{
177                   position: relative;
178                   display:inline-block;
179                   width:var(--atomic-dropdown-width, auto);
180                   z-index:100;
181                }
182
183                ::slotted([slot="click-element"]){
184                    cursor:pointer;
185                    user-select: none;
186                    z-index: 10;
187                    position: relative;
188                }
189
190                .slide-wrapper{
191                    position: fixed;
192                    top: -50%;
193                    left: -50%;
194                    width: 500px;
195                    max-width: 90vw;
196                    transform: translate(-50%, -50%);
197                    z-index: 999999;
198                }
199                .slide-wrapper-header {
200                    background-color: #45B0B9;
201                    height: 50px;
202                    border-top-left-radius: 5px;
203                    border-top-right-radius: 5px;
204                    display: flex;
205                    justify-content: flex-end;
206
207                }
208                #close-modal-btn {
209                    padding-right: 10px;
210                    border: none;
211                    background: transparent;
212                    color: #454545;
213                    font-size: 24px;
214                    font-weight: bold;
215                }
216                :host([open-left]) .slide-wrapper{
217                    right:0;
218                }
219                
220                :host([closed]) .slide-wrapper{
221                    overflow: hidden;
222                }
223                :host([opening]) .slide-wrapper,
224                :host([opened]) .slide-wrapper{
225                    overflow: visible;
226                    z-index: 200;
227                    top: 50%;
228                    left: 50%;
229                }
230                :host([opening]),
231                :host([opened]){
232                    z-index: 200;
233                }
234
235
236                .slide{
237                    transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out;
238                    position: absolute;
239                    top:0;
240                    box-sizing: border-box;
241                    display:block;
242                    overflow: hidden;
243                    max-height: 0px;
244                    opacity: 0;
245                    padding: 0;
246                    margin-left: 0;
247                    padding-top: var(--atomic-dropdown-space-top, 10px);
248                }
249                :host([openleft]) .slide{
250                    right:calc(var(--atomic-dropdown-outer-padding, 30px) * -1);
251                }
252                
253                :host([modal]) .slide{
254                    position: relative;
255                    max-height: none;
256                    overflow: visible;
257                }
258                    
259                :host([modal]) .dropdown-content {
260                    width: auto;
261                    padding: 20px;
262                }
263                
264                .slide-content{
265                    transition-timing-function: var(--atomic-dropdown-animation-function,ease-in-out);
266                    transition:var(--atomic-dropdown-animation-time,0.5s);
267                    transform: translateY(calc(-100% - var(--atomic-dropdown-space-top, 10px)));
268                    width:var(--atomic-dropdown-width, auto);
269                    box-sizing: border-box;
270                    background:var(--atomic-dropdown-content-background, white);
271                    padding: 0;
272                    border:var(--atomic-dropdown-border, none);
273                    margin-bottom: var(--atomic-dropdown-content-margin-bottom, 10px);
274                    border-top-left-radius: 5px;
275                    border-top-right-radius: 5px;
276                }
277
278                :host([animation="ease-in-out"]) .slide{
279                    transition: max-height 1s ease-in-out;
280                }
281                :host([opening]) .slide-content,
282                :host([opened]) .slide-content{
283                    transform: translateY(0%);
284                }
285
286                :host([animation="ease-in-out"][opened]) .slide{
287
288                }
289                :host([relative][opening]) .slide-wrapper,
290                :host([relative][opened]) .slide-wrapper{
291                   transform: translateY(0%);
292                }
293                :host([relative][opening]) .slide,
294                :host([relative][opened]) .slide{
295                    display: inline-block;
296                }
297                :host([opening]) .slide,
298                :host([opened]) .slide{
299                    max-height: 100vh !important;
300                    opacity: 1;
301                }
302                :host([relative][opening]) .slide-wrapper,
303                :host([relative][opening]) .slide,
304                :host([relative][opening]) .slide-content,
305                :host([relative][opened]) .slide-wrapper,
306                :host([relative][opened]) .slide,
307                :host([relative][opened]) .slide-content{
308                     position: relative;
309                }
310                ::slotted(ul){
311                    list-style: none;  
312                    margin:0; 
313                }
314            </style>
315            <slot name="click-element" part="click-element"></slot>
316            
317            <div class="slide-wrapper">
318                
319                
320                <div class="slide" part="list">
321                
322                    <div class="slide-content" part="list-inner">
323                    
324                    <div class="slide-wrapper-header">
325                        <button id="close-modal-btn" type="button" aria-label="Close">✕</button>
326                    </div>
327                    <slot></slot></div>
328                </div>
329            </div>
330        `;
331    }
332}
333
334if (customElements.get('atomic-dropdown') === undefined) {
335    customElements.define('atomic-dropdown', AtomicDropdown);
336}

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.