1jQuery(document).ready(function($) { 2 // Add spinner HTML after inputs 3 $('#developer-search').after('<div class="spinner-border" style="display: none;"></div>'); 4 5 // Add CSS for spinner 6 $('head').append(` 7<style> 8.spinner-border { 9width: 20px; 10height: 20px; 11border: 2px solid #f3f3f3; 12border-top: 2px solid #3498db; 13border-radius: 50%; 14animation: spin 1s linear infinite; 15display: inline-block; 16margin-left: 10px; 17vertical-align: middle; 18} 19 20@keyframes spin { 210% { transform: rotate(0deg); } 22100% { transform: rotate(360deg); } 23} 24 25#developer-filter { 26position: relative; 27display: flex; 28gap: 20px; 29align-items: center; 30margin-bottom: 20px; 31} 32 33.input-wrapper { 34position: relative; 35display: flex; 36align-items: center; 37} 38 39#load-more { 40position: relative; 41cursor: pointer; 42} 43 44#load-more .spinner-border { 45position: absolute; 46right: -30px; 47top: 50%; 48transform: translateY(-50%); 49} 50</style> 51`); 52 53 // Wrap inputs with a div for better spinner positioning 54 $('#developer-search, #area-filter').each(function() { 55 $(this).wrap('<div class="input-wrapper area-wrap"></div>'); 56 }); 57 58 function showSpinners() { 59 $('.spinner-border').show(); 60 $('#load-more').prop('disabled', true); 61 } 62 63 function hideSpinners() { 64 $('.spinner-border').hide(); 65 $('#load-more').prop('disabled', false); 66 } 67 68 function loadDevelopers(page = 1) { 69 if (document.getElementById('developers-list')) { 70 71 showSpinners(); 72 73 let search = $('#developer-search').val(); 74 let area = $('#area-filter').val(); 75 76 $.ajax({ 77 url: developerData.developer_ajax_url, 78 type: 'POST', 79 data: { 80 action: 'load_developers', 81 search: search, 82 area: area, 83 page: page, 84 security: developerData.developer_nonce 85 }, 86 success: function(response) { 87 let responseText = typeof response === 'string' ? response : JSON.stringify(response); 88 89 // If page = 1 (first load or filter change), replace 90 if (page === 1) { 91 $('#developers-list').html(responseText); 92 } else { 93 // Otherwise append to keep previously loaded developers 94 $('#developers-list').append(responseText); 95 } 96 97 // Handle "no results" 98 if ($.trim(responseText) === '' || responseText.toLowerCase().includes('no developers')) { 99 if (page === 1) { 100 $('#developers-list').html('<p>No developers match your search.</p>'); 101 } else { 102 $('#developers-list').append('<p>No more developers to load.</p>'); 103 } 104 } 105 }, 106 107 error: function(xhr) { 108 console.error('Error:', xhr.responseText); 109 }, 110 complete: function() { 111 hideSpinners(); 112 } 113 }); 114 } 115 116 117 118 } 119 120 // Initial load 121 loadDevelopers(); 122 123 // Add debounce function to prevent too many requests 124 function debounce(func, wait) { 125 let timeout; 126 return function() { 127 const context = this; 128 const args = arguments; 129 clearTimeout(timeout); 130 timeout = setTimeout(() => { 131 func.apply(context, args); 132 }, wait); 133 }; 134 } 135 136 137 138 // Use debounce for search input 139 const debouncedLoad = debounce(function() { 140 $('#load-more').data('page', 1); 141 loadDevelopers(); 142 }, 300); 143 144 $('#developer-search').on('input', debouncedLoad); 145 146 // Immediate load for dropdown 147 $('#area-filter').on('change', function() { 148 $('#load-more').data('page', 1); 149 loadDevelopers(); 150 }); 151 152 // Add spinner to load more button 153 $('#load-more').append('<div class="spinner-border" style="display: none;"></div>'); 154 155 $('#load-more').on('click', function() { 156 let nextPage = $(this).data('page') + 1; 157 $(this).data('page', nextPage); 158 loadDevelopers(nextPage); 159 }); 160}); 161 162jQuery(document).ready(function ($) { 163 164 function loadDeveloperProjects(page = 1) { 165 if (document.getElementById('projects-list')) { 166 167 // Show spinner 168 $('#load-more-projects .spinner-border').show(); 169 $('#load-more-projects').prop('disabled', true); 170 171 const developerId = $('#developer-projects').data('developer-id'); 172 173 $.ajax({ 174 url: developerData.developer_ajax_url, 175 type: 'POST', 176 data: { 177 action: 'load_developer_projects', 178 developer_id: developerId, 179 page: page, 180 security: developerData.developer_nonce, 181 }, 182 success: function (response) { 183 if (response.success) { 184 if (page === 1) { 185 $('#projects-list').html(response.data.html); 186 } else { 187 $('#projects-list').append(response.data.html); 188 } 189 190 // Check if more projects are available 191 if (response.data.has_more) { 192 $('#load-more-projects').data('page', page + 1).prop('disabled', false); 193 } else { 194 $('#load-more-projects').hide(); 195 } 196 } else { 197 console.error('No projects found.'); 198 } 199 }, 200 error: function (xhr) { 201 console.error('Error:', xhr.responseText); 202 }, 203 complete: function () { 204 $('#load-more-projects .spinner-border').hide(); 205 }, 206 }); 207 } 208 209 210 } 211 212 // Initial load for developer projects 213 loadDeveloperProjects(); 214 215 // Handle "Load More Projects" button click 216 $('#load-more-projects').on('click', function () { 217 const nextPage = $(this).data('page'); 218 loadDeveloperProjects(nextPage); 219 }); 220});
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.