PageSourceSearch

https://itamde.com/wp-content/themes/d4f-divi/includes/divi-modules/AdvancedPostGrid/script.js?ver=1.0.9

js itamde.com collected 2026-09-24 12:32:44 UTC 11,215 bytes, 297 lines download raw bytes

1/**
2 * Advanced Post Grid Module JavaScript
3 * Handles AJAX filters, pagination and load more
4 */
5
6(function($) {
7    'use strict';
8
9    // Class to manage the Post Grid
10    class D4FPostGrid {
11        constructor(element) {
12            this.$element = $(element);
13            this.moduleId = this.$element.attr('id');
14            this.$container = this.$element.find('.d4f-post-grid-container');
15            this.$filters = this.$element.find('.d4f-filters');
16            this.$pagination = this.$element.find('.d4f-pagination');
17
18            // Settings from module data attributes
19            this.settings = {
20                postType: this.$element.data('post-type') || 'post',
21                perPage: this.$element.data('per-page') || 9,
22                layout: this.$element.data('layout') || 'grid',
23                columns: this.$element.data('columns') || 3,
24                showImage: this.$element.data('show-image') || 'on',
25                showExcerpt: this.$element.data('show-excerpt') || 'on',
26                excerptLength: this.$element.data('excerpt-length') || 20,
27                showDate: this.$element.data('show-date') || 'on',
28                showAuthor: this.$element.data('show-author') || 'off',
29                showCategories: this.$element.data('show-categories') || 'on',
30                orderBy: this.$element.data('order-by') || 'date',
31                order: this.$element.data('order') || 'DESC',
32                categoryFilter: this.$element.data('category-filter') || '',
33                filterCategories: this.$element.data('filter-categories') || '',
34                currentLang: this.$element.data('current-lang') || '',
35                excludePosts: this.$element.data('exclude-posts') || ''
36            };
37
38            this.currentPage = 1;
39            this.currentCategory = 'all';
40            this.isLoading = false;
41
42            this.init();
43        }
44
45        init() {
46            this.bindEvents();
47        }
48
49        bindEvents() {
50            // Button filters
51            this.$filters.on('click', '.d4f-filter-btn', (e) => {
52                e.preventDefault();
53                const $btn = $(e.currentTarget);
54                const category = $btn.data('cat');
55
56                // Update UI
57                this.$filters.find('.d4f-filter-btn').removeClass('active');
58                $btn.addClass('active');
59
60                // Load posts
61                this.currentCategory = category;
62                this.currentPage = 1;
63                this.loadPosts(true);
64            });
65
66            // Dropdown filter
67            this.$filters.on('change', '.d4f-filter-select', (e) => {
68                const category = $(e.currentTarget).val();
69                this.currentCategory = category;
70                this.currentPage = 1;
71                this.loadPosts(true);
72            });
73
74            // AJAX pagination
75            this.$pagination.on('click', 'a', (e) => {
76                if (this.$pagination.hasClass('d4f-pagination-ajax')) {
77                    e.preventDefault();
78                    const $link = $(e.currentTarget);
79                    const href = $link.attr('href');
80
81                    // Extract page number from URL
82                    const match = href.match(/[?&]pg=(\d+)/);
83                    if (match) {
84                        this.currentPage = parseInt(match[1]);
85                        this.loadPosts(true);
86
87                        // Scroll to top
88                        $('html, body').animate({
89                            scrollTop: this.$element.offset().top - 100
90                        }, 500);
91                    }
92                }
93            });
94
95            // Load More button
96            this.$pagination.on('click', '.d4f-load-more-btn', (e) => {
97                e.preventDefault();
98                const $btn = $(e.currentTarget);
99                this.currentPage = parseInt($btn.data('page'));
100                this.loadPosts(false); // append, non replace
101            });
102        }
103
104        loadPosts(replace = true) {
105            if (this.isLoading) {
106                return;
107            }
108
109            this.isLoading = true;
110
111            // Loading state
112            if (replace) {
113                this.$container.addClass('d4f-loading');
114            } else {
115                this.$pagination.find('.d4f-load-more-btn')
116                    .text(d4fPostGrid.i18n.loading)
117                    .prop('disabled', true);
118            }
119
120            // AJAX request
121            $.ajax({
122                url: d4fPostGrid.ajaxurl,
123                type: 'POST',
124                data: {
125                    action: 'd4f_load_posts',
126                    nonce: d4fPostGrid.nonce,
127                    post_type: this.settings.postType,
128                    posts_per_page: this.settings.perPage,
129                    page: this.currentPage,
130                    category: this.currentCategory,
131                    category_filter: this.settings.categoryFilter,
132                    filter_categories: this.settings.filterCategories,
133                    lang: this.settings.currentLang,
134                    exclude_posts: this.settings.excludePosts,
135                    order_by: this.settings.orderBy,
136                    order: this.settings.order,
137                    show_image: this.settings.showImage,
138                    show_excerpt: this.settings.showExcerpt,
139                    excerpt_length: this.settings.excerptLength,
140                    show_date: this.settings.showDate,
141                    show_author: this.settings.showAuthor,
142                    show_categories: this.settings.showCategories,
143                },
144                success: (response) => {
145                    this.isLoading = false;
146                    this.$container.removeClass('d4f-loading');
147
148                    if (response.success) {
149                        if (replace) {
150                            // Replace all content
151                            this.$container.fadeOut(200, () => {
152                                this.$container.html(response.html);
153                                this.$container.fadeIn(200);
154                            });
155                        } else {
156                            // Append (load more)
157                            const $newPosts = $(response.html);
158                            $newPosts.hide().appendTo(this.$container).fadeIn(400);
159                        }
160
161                        // Update pagination
162                        this.updatePagination(response);
163                    } else {
164                        this.$container.html('<p class="d4f-no-posts">' + d4fPostGrid.i18n.noContent + '</p>');
165                        this.$pagination.html('');
166                    }
167                },
168                error: (xhr, status, error) => {
169                    this.isLoading = false;
170                    this.$container.removeClass('d4f-loading');
171                    console.error('AJAX Error:', error);
172                    alert(d4fPostGrid.i18n.error);
173                }
174            });
175        }
176
177        updatePagination(response) {
178            const $loadMoreBtn = this.$pagination.find('.d4f-load-more-btn');
179
180            if ($loadMoreBtn.length) {
181                // Load More type
182                if (response.has_more) {
183                    $loadMoreBtn
184                        .data('page', response.current_page + 1)
185                        .text(d4fPostGrid.i18n.loadMore)
186                        .prop('disabled', false);
187                } else {
188                    $loadMoreBtn.fadeOut();
189                }
190            } else if (this.$pagination.hasClass('d4f-pagination-ajax')) {
191                // Numbered AJAX pagination
192                this.generatePagination(response.current_page, response.max_pages);
193            }
194        }
195
196        generatePagination(currentPage, maxPages) {
197            if (maxPages <= 1) {
198                this.$pagination.html('');
199                return;
200            }
201
202            let html = '<ul>';
203
204            // Previous
205            if (currentPage > 1) {
206                html += `<li><a href="?pg=${currentPage - 1}">←</a></li>`;
207            }
208
209            // Pages
210            const range = 2; // Show 2 pages before and after
211            let start = Math.max(1, currentPage - range);
212            let end = Math.min(maxPages, currentPage + range);
213
214            // First page
215            if (start > 1) {
216                html += `<li><a href="?pg=1">1</a></li>`;
217                if (start > 2) {
218                    html += '<li><span>...</span></li>';
219                }
220            }
221
222            // Page numbers
223            for (let i = start; i <= end; i++) {
224                if (i === currentPage) {
225                    html += `<li><span class="current">${i}</span></li>`;
226                } else {
227                    html += `<li><a href="?pg=${i}">${i}</a></li>`;
228                }
229            }
230
231            // Last page
232            if (end < maxPages) {
233                if (end < maxPages - 1) {
234                    html += '<li><span>...</span></li>';
235                }
236                html += `<li><a href="?pg=${maxPages}">${maxPages}</a></li>`;
237            }
238
239            // Next
240            if (currentPage < maxPages) {
241                html += `<li><a href="?pg=${currentPage + 1}">→</a></li>`;
242            }
243
244            html += '</ul>';
245            this.$pagination.html(html);
246        }
247    }
248
249    // Initialize all Advanced Post Grid modules
250    function initPostGrids() {
251        $('.d4f-advanced-post-grid').each(function() {
252            // Prevent double initialization
253            if (!$(this).data('d4f-initialized')) {
254                new D4FPostGrid(this);
255                $(this).data('d4f-initialized', true);
256            }
257        });
258    }
259
260    // Init on document ready
261    $(document).ready(function() {
262        initPostGrids();
263    });
264
265    // Re-init for Divi Visual Builder (safe approach)
266    $(window).on('et_builder_api_ready', function(event, API) {
267        // Safely handle API if it exists
268        if (typeof API !== 'undefined') {
269            console.log('Divi Builder API ready');
270        }
271
272        // Use MutationObserver for detecting DOM changes in Visual Builder
273        // This works independently of the API object
274        const observer = new MutationObserver(function(mutations) {
275            mutations.forEach(function(mutation) {
276                if (mutation.addedNodes.length) {
277                    initPostGrids();
278                }
279            });
280        });
281
282        // Observe the body for changes
283        observer.observe(document.body, {
284            childList: true,
285            subtree: true
286        });
287
288        // Fallback: init immediately
289        setTimeout(initPostGrids, 500);
290    });
291
292    // Additional init for when module is loaded/reloaded in Visual Builder
293    $(window).on('load', function() {
294        setTimeout(initPostGrids, 1000);
295    });
296
297})(jQuery);

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.