PageSourceSearch

https://cvillehabitat.org/wp-content/themes/hfh/js/project-crousal.js?ver=2.0

js cvillehabitat.org collected 2026-09-26 08:53:11 UTC 8,394 bytes, 202 lines download raw bytes

1jQuery(document).ready(function ($) {
2
3    const postsPerPage = 3;
4
5    $('.project-wrapper').each(function () {
6        const section = $(this);
7        const category = section.data('category');
8        const uid = section.attr('id');
9
10        let postsLoaded = 0;
11
12        // Load initial
13        loadProjects('init');
14
15        // === Buttons ===
16        section.find('.showMoreBtn').on('click', function () {
17            loadProjects('more');
18        });
19        section.find('.showAllBtn').on('click', function () {
20            loadProjects('all');
21        });
22        section.find('.showLessBtn').on('click', function () {
23            var locationEle = $(this).data('location');
24            loadProjects('less',locationEle);
25        });
26
27        // === Function: Load Projects ===
28        function loadProjects(type,target = '') {
29            let offsetToSend = 0;
30            
31            let perPageToSend = postsPerPage;
32
33            if (type === 'more') {
34                offsetToSend = postsLoaded;
35            } else if (['less', 'init'].includes(type)) {
36                offsetToSend = 0;
37            } else if (type === 'all') {
38                offsetToSend = 0;
39                perPageToSend = -1;
40            }
41
42            var headerHeight = $('#main-header').outerHeight();
43
44            $.ajax({
45                url: projectCrousalAjax.ajax_url,
46                type: 'POST',
47                dataType: 'json',
48                data: {
49                    action: 'load_projects_grid',
50                    category: category,
51                    type: type,
52                    offset: offsetToSend,
53                    per_page: perPageToSend,
54                    
55                },
56                success: function (response) {
57                    if (!response.success) return;
58
59                    const data = response.data;
60                    const cards = section.find('.projectCards');
61
62                    if (['less', 'init', 'all'].includes(type)) {
63                        cards.html(data.html);
64                    } else if (type === 'more') {
65                        cards.append(data.html);
66                    }
67
68                    postsLoaded = data.loaded;
69
70                    // Button logic
71                    const btnMore = section.find('.showMoreBtn');
72                    const btnAll = section.find('.showAllBtn');
73                    const btnLess = section.find('.showLessBtn');
74
75                    if (['less', 'init'].includes(type)) {
76                        btnMore.removeClass('d-none');
77                        btnAll.removeClass('d-none');
78                        btnLess.addClass('d-none');
79
80                        console.log(target);
81                        if(target != ''){
82                            //$('[data-link="#'+target+'"]').trigger('click');
83                            var headerHeight = $('#main-header').outerHeight();
84                            $('html, body').animate({
85                                scrollTop: $('#'+target).offset().top - headerHeight - 100
86                            }, 600);
87                        }
88
89                    } else if (type === 'more') {
90                        if (data.all_loaded || !data.html.trim()) {
91                            btnMore.addClass('d-none');
92                            btnAll.addClass('d-none');
93                            btnLess.removeClass('d-none');
94                        } else {
95                            btnMore.removeClass('d-none');
96                            btnAll.addClass('d-none');
97                            btnLess.addClass('d-none');
98                        }
99                    } else if (type === 'all') {
100                        btnMore.addClass('d-none');
101                        btnAll.addClass('d-none');
102                        btnLess.removeClass('d-none');
103                    }
104
105                    bindReadMore();
106                }
107            });
108        }
109
110        // === Function: Bind Read More Buttons ===
111        function bindReadMore() {
112            section.find('.read-more-btn').off('click').on('click', function () {
113                const postID = $(this).data('id');
114                openProjectPopup(postID);
115            });
116        }
117
118        function openProjectPopup(postID){
119            const modal = $('#modal_projects');
120            $.ajax({
121                    url: projectCrousalAjax.ajax_url,
122                    type: 'POST',
123                    dataType: 'json',
124                    data: {
125                        action: 'load_project_details',
126                        post_id: postID
127                    },
128                    success: function (response) {
129                        if (!response.success) return;
130                        const data = response.data;
131
132                       const modalBody = modal.find('.modal-body');
133
134                        // === Build Carousel ===
135                        let carouselHTML = '';
136                        if (data.images && data.images.length > 0) {
137                            carouselHTML = `
138                                <div id="projectCarousel" class="carousel slide mb-4" data-bs-ride="carousel">
139                                        <div class="carousel-inner">
140                                            ${data.images.map((img, index) => `
141                                                <div class="carousel-item ${index === 0 ? 'active' : ''}">
142                                                    <img src="${img}" class="d-block w-100 rounded" alt="Project Image">
143                                                </div>
144                                            `).join('')}
145                                        </div>
146
147                                        ${
148                                            data.images.length > 1
149                                            ? `
150                                                <button class="carousel-control-prev" type="button" data-bs-target="#projectCarousel" data-bs-slide="prev">
151                                                    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
152                                                </button>
153                                                <button class="carousel-control-next" type="button" data-bs-target="#projectCarousel" data-bs-slide="next">
154                                                    <span class="carousel-control-next-icon" aria-hidden="true"></span>
155                                                </button>
156                                            `
157                                            : ''
158                                        }
159                                    </div>
160                                `;
161                        } else {
162                            carouselHTML = '<div> <p class="text-center text-muted mb-4">No images available.</p>';
163                        }
164
165                        // === Build Title + Content Section ===
166                        const detailsHTML = `
167                            <div class="project-info">
168                                <h4 class="fw-bold mb-2">${data.title}</h4>
169                                <div class="project-description">${data.content}</div>
170                            </div>
171                            </div>
172                        `;
173
174                        modalBody.html(carouselHTML + detailsHTML);
175
176                        const modalInstance = new bootstrap.Modal(modal[0], {
177                            backdrop: true, // ✅ Disable background overlay
178                            //keyboard: true   // (optional) still allow Esc to close
179                        });
180                        modalInstance.show();
181                    }
182            });
183        }
184
185        const projectId = window.location.hash.substring(1);
186        if (typeof projectId !== "undefined" && projectId !== null && projectId !== "") {
187            openProjectPopup(projectId);
188        }
189        $(document).on('click', '.project-page-read-more-btn', function(e) {
190            e.preventDefault(); // stop normal navigation
191            let postID = $(this).data('id');
192            openProjectPopup(postID);
193        });        
194    });
195
196    $('#modal_projects').on('hidden.bs.modal', function () {
197        $('body').css({
198            'overflow': 'auto',
199            'padding-right': '0'
200        });
201    });
202});

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.