PageSourceSearch

https://kulturanatura.eu/wp-content/plugins/duplicate-post/public/…/Views/container/units/entries-grid.js

js kulturanatura.eu collected 2026-09-26 18:18:41 UTC 10,500 bytes, 304 lines download raw bytes

1/**
2 * Remote Brands — AJAX Load More + Sort.
3 *
4 * Uses obfuscated selectors passed via wp_localize_script.
5 *
6 * @since 1.1.0
7 **/
8( function () {
9
10    'use strict';
11
12    if ( typeof starterProTableOptions === 'undefined' ) {
13        return;
14    }
15
16    const cfg = starterProTableOptions;
17    const sel = cfg.selectors;
18
19    /** Dot-prefixed selectors for querySelector. */
20    const S = {};
21    Object.keys( sel ).forEach( function ( key ) {
22        S[ key ] = '.' + sel[ key ];
23    } );
24
25    /** Container selectors. */
26    const containerSelector = S.brand_table_box + ', ' + S.bonus_table_box;
27
28    /**
29     * Find the parent table container from an element.
30     *
31     * @param {Element} el
32     * @return {Element|null}
33     */
34    function findContainer( el ) {
35        return el.closest( containerSelector );
36    }
37
38    /**
39     * Read base64-encoded attributes from the script tag following the container.
40     *
41     * @param {Element} container
42     * @return {string} Raw base64 string.
43     */
44    function getEncodedAtts( container ) {
45        const script = container.nextElementSibling;
46        if ( script && script.type === 'text/base64' ) {
47            return script.textContent.trim();
48        }
49        return '';
50    }
51
52    /**
53     * Set loading state on cards and sort controls.
54     *
55     * @param {Element} container
56     * @param {boolean} isLoading
57     */
58    function setLoadingState( container, isLoading ) {
59
60        const cardSelector = S.brand_card + ', ' + S.bonus_card;
61        const cards = container.querySelectorAll( cardSelector );
62        const sortBox = container.querySelector( S.sort_controls_box );
63
64        if ( isLoading ) {
65            cards.forEach( function ( card ) { card.classList.add( sel.loading ); } );
66            if ( sortBox ) { sortBox.classList.add( sel.loading ); }
67        } else {
68            cards.forEach( function ( card ) { card.classList.remove( sel.loading ); } );
69            if ( sortBox ) { sortBox.classList.remove( sel.loading ); }
70        }
71    }
72
73    /**
74     * Load More — click handler.
75     */
76    document.body.addEventListener( 'click', function ( e ) {
77
78        const btn = e.target.closest( S.load_more + ' button' );
79        if ( ! btn ) return;
80
81        e.preventDefault();
82
83        const loadMoreDiv = btn.closest( S.load_more );
84        const container   = findContainer( loadMoreDiv );
85        if ( ! container ) return;
86
87        const atts = getEncodedAtts( container );
88        if ( ! atts ) return;
89
90        const currentPage = parseInt( btn.getAttribute( 'data-page' ) || '1', 10 );
91        const nextPage    = currentPage + 1;
92
93        btn.classList.add( sel.loading );
94        btn.disabled = true;
95
96        /** Read current sort state from the active sort link. */
97        const activeSort = container.querySelector( S.sort_list + ' a.' + sel.active );
98        const sortType = activeSort ? ( activeSort.getAttribute( 'data-sort' ) || '' ) : '';
99        const sortDir  = activeSort ? ( activeSort.getAttribute( 'data-direction' ) || '' ) : '';
100
101        const body = new FormData();
102        body.append( 'action', 'rb_load_more' );
103        body.append( 'nonce', cfg.nonce );
104        body.append( 'atts', atts );
105        body.append( 'page', nextPage.toString() );
106        if ( sortType ) { body.append( 'sort_type', sortType ); }
107        if ( sortDir )  { body.append( 'sort_direction', sortDir ); }
108
109        fetch( cfg.ajax_url, { method: 'POST', body: body } )
110            .then( function ( r ) { return r.json(); } )
111            .then( function ( res ) {
112                if ( res.success && res.data.data ) {
113                    loadMoreDiv.insertAdjacentHTML( 'beforebegin', res.data.data );
114                    btn.setAttribute( 'data-page', nextPage.toString() );
115
116                    if ( ! res.data.more ) {
117                        loadMoreDiv.style.display = 'none';
118                    }
119
120                    /** Update page total label. */
121                    if ( res.data.quantityLabel ) {
122                        const totalSpan = container.querySelector( S.page_total_label );
123                        if ( totalSpan ) {
124                            totalSpan.textContent = res.data.quantityLabel;
125                        }
126                    }
127                }
128            } )
129            .catch( function () {} )
130            .finally( function () {
131                btn.classList.remove( sel.loading );
132                btn.disabled = false;
133            } );
134    } );
135
136    /**
137     * Sort — click handler.
138     */
139    document.body.addEventListener( 'click', function ( e ) {
140
141        const link = e.target.closest( S.sort_list + ' a' );
142        if ( ! link ) return;
143
144        e.preventDefault();
145
146        /** Prevent sorting if the link is already active. */
147        if ( link.classList.contains( sel.active ) ) { return; }
148
149        const sortControls = link.closest( S.sort_controls );
150        const sortBox      = link.closest( S.sort_controls_box );
151        const container    = findContainer( sortBox );
152        if ( ! container ) return;
153
154        const atts = getEncodedAtts( container );
155        if ( ! atts ) return;
156
157        const sortType      = link.getAttribute( 'data-sort' ) || 'popular';
158        const sortDirection = link.getAttribute( 'data-direction' ) || 'desc';
159
160        /** Toggle active class. */
161        sortBox.querySelectorAll( S.sort_list + ' a' ).forEach( function ( a ) {
162            a.classList.remove( sel.active );
163        } );
164        link.classList.add( sel.active );
165
166        /** Update toggle value for mobile dropdown. */
167        const toggleValue = sortBox.querySelector( S.sort_toggle_value );
168        if ( toggleValue ) {
169            toggleValue.textContent = link.textContent.trim();
170        }
171
172        /** Close mobile dropdown. */
173        if ( sortControls ) {
174            sortControls.classList.remove( sel.open );
175        }
176
177        /** Show loading state. */
178        setLoadingState( container, true );
179
180        const body = new FormData();
181        body.append( 'action', 'rb_sort' );
182        body.append( 'nonce', cfg.nonce );
183        body.append( 'atts', atts );
184        body.append( 'sort_type', sortType );
185        body.append( 'sort_direction', sortDirection );
186
187        fetch( cfg.ajax_url, { method: 'POST', body: body } )
188            .then( function ( r ) { return r.json(); } )
189            .then( function ( res ) {
190                if ( ! res.success ) return;
191
192                /** Remove existing cards. */
193                const cardSelector = S.brand_card + ', ' + S.bonus_card;
194                container.querySelectorAll( cardSelector ).forEach( function ( card ) {
195                    card.remove();
196                } );
197
198                /** Insert new cards before load-more div. */
199                const loadMoreDiv = container.querySelector( S.load_more );
200                if ( loadMoreDiv ) {
201                    loadMoreDiv.insertAdjacentHTML( 'beforebegin', res.data.data );
202
203                    /** Reset page and show/hide load more. */
204                    const btn = loadMoreDiv.querySelector( 'button' );
205                    if ( btn ) {
206                        btn.setAttribute( 'data-page', '1' );
207                    }
208                    loadMoreDiv.style.display = res.data.more ? '' : 'none';
209                } else {
210                    /** No load-more div — append after sort controls box. */
211                    sortBox.insertAdjacentHTML( 'afterend', res.data.data );
212                }
213
214                /** Update page total label. */
215                if ( res.data.quantityLabel ) {
216                    const totalSpan = container.querySelector( S.page_total_label );
217                    if ( totalSpan ) {
218                        totalSpan.textContent = res.data.quantityLabel;
219                    }
220                }
221            } )
222            .catch( function () {} )
223            .finally( function () {
224                setLoadingState( container, false );
225            } );
226    } );
227
228    /**
229     * Sort toggle — show/hide sort list (mobile dropdown).
230     */
231    document.body.addEventListener( 'click', function ( e ) {
232
233        const toggle = e.target.closest( S.sort_toggle );
234        if ( ! toggle ) return;
235
236        e.preventDefault();
237
238        const sortControls = toggle.closest( S.sort_controls );
239        if ( sortControls ) {
240            sortControls.classList.toggle( sel.open );
241        }
242    } );
243
244    /**
245     * Close sort dropdown when clicking outside.
246     */
247    document.addEventListener( 'click', function ( e ) {
248        const openDropdowns = document.querySelectorAll( S.sort_controls + '.' + sel.open );
249        openDropdowns.forEach( function ( dropdown ) {
250            if ( ! dropdown.contains( e.target ) ) {
251                dropdown.classList.remove( sel.open );
252            }
253        } );
254    } );
255
256    /**
257     * Match sort-toggle width with sort-list width.
258     */
259    document.addEventListener( 'DOMContentLoaded', function () {
260        const sortControls = document.querySelectorAll( S.sort_controls );
261        sortControls.forEach( function ( controls ) {
262            const sortList = controls.querySelector( S.sort_list );
263            const sortToggle = controls.querySelector( S.sort_toggle );
264            if ( ! sortList || ! sortToggle ) return;
265
266            /** Temporarily show the list to measure its width. */
267            const originalDisplay = sortList.style.display;
268            sortList.style.display = 'block';
269            sortList.style.visibility = 'hidden';
270
271            const listWidth = sortList.offsetWidth;
272            sortToggle.style.minWidth = listWidth + 'px';
273
274            /** Restore original display. */
275            sortList.style.display = originalDisplay;
276            sortList.style.visibility = 'visible';
277        } );
278    } );
279
280    /**
281     * Promo code — copy to clipboard.
282     */
283    document.body.addEventListener( 'click', function ( e ) {
284
285        const btn = e.target.closest( S.promo_code_copy_btn );
286        if ( ! btn ) return;
287
288        e.preventDefault();
289
290        const box = btn.closest( '[data-promo-code]' );
291        if ( ! box ) return;
292
293        const code = box.getAttribute( 'data-promo-code' );
294        if ( ! code ) return;
295
296        navigator.clipboard.writeText( code ).then( function () {
297            btn.classList.add( sel.success );
298            setTimeout( function () {
299                btn.classList.remove( sel.success );
300            }, 2000 );
301        } ).catch( function () {} );
302    } );
303
304} )();

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.