https://www.dneph.com/wp-content/plugins/dneph-pressganey-reviews/assets/js/script.js?ver=1790291962
1/** 2 * PressGaney Reviews Plugin JavaScript 3 * Handles AJAX requests, UI interactions, and dynamic content loading 4 */ 5 6(function($) { 7 'use strict'; 8 9 // Main plugin object 10 var PressGaneyReviews = { 11 12 // Initialize the plugin 13 init: function() { 14 this.bindEvents(); 15 this.initializeReviews(); 16 }, 17 18 // Bind event listeners 19 bindEvents: function() { 20 $(document).on('click', '.pressganey-load-more-button', this.handleLoadMore); 21 $(document).on('click', '.pressganey-copy-shortcode', this.copyToClipboard); 22 $(document).on('click', '#force-sync', this.handleForceSync); 23 }, 24 25 // Initialize reviews containers (no longer needed for AJAX, but kept for future use) 26 initializeReviews: function() { 27 // Reviews are now loaded server-side, so no initialization needed 28 // This function is kept for backward compatibility and future enhancements 29 }, 30 31 // Reviews are now loaded server-side, so this function is no longer needed 32 // Kept for backward compatibility 33 loadReviews: function(container, entityType, entityId, displayType) { 34 // Reviews are now rendered server-side in the template 35 console.log('Reviews loaded server-side for entity:', entityId); 36 }, 37 38 // Generate basic display HTML (no longer used - reviews rendered server-side) 39 generateBasicDisplay: function(entity) { 40 console.log('generateBasicDisplay called - reviews now rendered server-side'); 41 return ''; 42 }, 43 44 // Generate reviews display HTML (no longer used - reviews rendered server-side) 45 generateReviewsDisplay: function(entity) { 46 console.log('generateReviewsDisplay called - reviews now rendered server-side'); 47 return ''; 48 }, 49 50 // Generate star rating HTML 51 generateStars: function(rating) { 52 var fullStars = Math.floor(rating); 53 var hasHalfStar = rating % 1 >= 0.5; 54 var emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); 55 56 var stars = 'â '.repeat(fullStars); 57 if (hasHalfStar) stars += 'â'; 58 stars += 'â'.repeat(emptyStars); 59 60 return stars; 61 }, 62 63 // Handle load more button click (updated for server-side data) 64 handleLoadMore: function(e) { 65 e.preventDefault(); 66 67 var button = $(this); 68 var container = button.closest('.pressganey-reviews-container'); 69 var reviewsList = container.find('.pressganey-reviews-list'); 70 var currentIndex = parseInt(button.data('current-index')) || 6; 71 var totalReviews = parseInt(button.data('total-reviews')) || 0; 72 73 // Get all reviews from the button's data attribute (now stored there) 74 var allReviews = []; 75 try { 76 var encodedData = button.data('reviews-data') || ''; 77 if (encodedData) { 78 // Decode base64 data 79 var decodedString = decodeURIComponent(escape(atob(encodedData))); 80 allReviews = JSON.parse(decodedString); 81 } 82 } catch (e) { 83 console.error('Error parsing reviews data:', e); 84 console.error('Encoded data:', encodedData); 85 return; 86 } 87 88 button.prop('disabled', true).text('Loading...'); 89 90 // Calculate how many reviews to show next 91 var nextBatch = allReviews.slice(currentIndex, currentIndex + 6); 92 var newIndex = currentIndex + nextBatch.length; 93 94 if (nextBatch.length > 0) { 95 var startIndex = reviewsList.children().length; 96 97 // Add each review in the next batch 98 for (var i = 0; i < nextBatch.length; i++) { 99 var review = nextBatch[i]; 100 var reviewRating = review.overallRating ? review.overallRating.value : 0; 101 var reviewDate = new Date(review.mentionTime).toLocaleDateString('en-US', { 102 year: 'numeric', 103 month: 'short', 104 day: 'numeric' 105 }); 106 107 var commentText = (review.comment && typeof review.comment === 'object') 108 ? review.comment.comment 109 : review.comment; 110 111 commentText = commentText || ''; 112 113 var reviewHtml = '<li class="pressganey-review-item pressganey-slide-in" style="animation-delay: ' + ((startIndex + i
113) * 0.1) + 's">' + 114 '<div class="pressganey-review-header">' + 115 '<div class="pressganey-review-stars" data-rating="' + reviewRating + '">' + 116 PressGaneyReviews.generateStars(reviewRating) + '</div>' + 117 '<div class="pressganey-review-date">' + reviewDate + '</div>' + 118 '</div>' + 119 '<p class="pressganey-review-comment">' + PressGaneyReviews.escapeHtml(commentText) + '</p>' + 120 '</li>'; 121 122 reviewsList.append(reviewHtml); 123 } 124 125 // Update button data 126 button.data('current-index', newIndex); 127 128 // Hide button if no more reviews to show 129 if (newIndex >= totalReviews) { 130 button.parent().fadeOut(); 131 } 132 } 133 134 button.prop('disabled', false).text('Load More Reviews'); 135 }, 136 137 // Bind load more functionality 138 bindLoadMore: function(container, entityType, entityId, displayType, scrollKey) { 139 // The load more functionality is now handled by the document-level event listener 140 // No additional binding needed since we're using event delegation 141 }, 142 143 // Copy shortcode to clipboard 144 copyToClipboard: function(e) { 145 e.preventDefault(); 146 147 var shortcode = $(this).siblings('input').val(); 148 if (shortcode) { 149 if (navigator.clipboard && window.isSecureContext) { 150 navigator.clipboard.writeText(shortcode).then(function() { 151 PressGaneyReviews.showNotification('Shortcode copied to clipboard!', 'success'); 152 }).catch(function() { 153 PressGaneyReviews.fallbackCopyTextToClipboard(shortcode); 154 }); 155 } else { 156 PressGaneyReviews.fallbackCopyTextToClipboard(shortcode); 157 } 158 } 159 }, 160 161 // Fallback copy method for older browsers 162 fallbackCopyTextToClipboard: function(text) { 163 var textArea = document.createElement('textarea'); 164 textArea.value = text; 165 textArea.style.top = '0'; 166 textArea.style.left = '0'; 167 textArea.style.position = 'fixed'; 168 document.body.appendChild(textArea); 169 textArea.focus(); 170 textArea.select(); 171 172 try { 173 document.execCommand('copy'); 174 this.showNotification('Shortcode copied to clipboard!', 'success'); 175 } catch (err) { 176 this.showNotification('Failed to copy shortcode', 'error'); 177 } 178 179 document.body.removeChild(textArea); 180 }, 181 182 // Show notification 183 showNotification: function(message, type) { 184 var notification = $('<div class="pressganey-notification pressganey-notification-' + type + '">' + message + '</div>'); 185 186 $('body').append(notification); 187 188 setTimeout(function() { 189 notification.addClass('pressganey-notification-show'); 190 }, 100); 191 192 setTimeout(function() { 193 notification.removeClass('pressganey-notification-show'); 194 setTimeout(function() { 195 notification.remove(); 196 }, 300); 197 }, 3000); 198 }, 199 200 // Handle force sync button click 201 handleForceSync: function(e) { 202 e.preventDefault(); 203 204 var button = $(this); 205 var syncText = button.find('.sync-text'); 206 var syncLoading = button.find('.sync-loading'); 207 var syncResult = $('#sync-result'); 208 209 // Show loading state 210 button.prop('disabled', true); 211 syncText.hide(); 212 syncLoading.show(); 213 syncResult.hide(); 214 215 $.ajax({ 216 url: pressganey_ajax.ajax_url, 217 type: 'POST', 218 data: { 219 action: 'pressganey_force_sync', 220 nonce: pressganey_ajax.nonce 221 }, 222 success: function(response) { 223 if (response.success) { 224 var html = '<div class="notice notice-success"><p>' + response.data.message + '</p></div>'; 225 226 // Add debug information if available 227 if (response.data.debug && response.data.debug.length > 0) { 228 html += '<div class="sync-debug">'; 229 html += '<h4>Debug Information:</h4>'; 230 html += '<div style="background: #f0f0f0; padding: 10px; border-radius: 4px; max-height: 300px; overflow-y: auto; font-family: monospace; font-size: 12px; white-space: pre-wrap;">'; 231 232 for (var i = 0; i < response.data.debug.length; i++) { 233 html += response.data.debug[i] + '\n'; 234 } 235 236 html += '</div>'; 237 html += '</div>'; 238 } 239 240 syncResult.html(html).show(); 241 PressGaneyReviews.showNotification('Sync completed successfully!', 'success'); 242 } else { 243 var errorData = typeof response.data === 'object' ? response.data : { message: response.data }; 244 var html = '<div class="notice notice-error"><p>' + errorData.message + '</p></div>'; 245 246 // Add debug information if available 247 if (errorData.debug && errorData.debug.length > 0) { 248 html += '<div class="sync-debug">'; 249 html += '<h4>Debug Information:</h4>'; 250 html += '<div style="background: #f0f0f0; padding: 10px; border-radius: 4px; max-height: 300px; overflow-y: auto; font-family: monospace; font-size: 12px; white-space: pre-wrap;">'; 251 252 for (var i = 0; i < errorData.debug.length; i++) { 253 html += errorData.debug[i] + '\n'; 254 } 255 256 html += '</div>'; 257 html += '</div>'; 258 } 259 260 syncResult.html(html).show(); 261 PressGaneyReviews.showNotification('Sync failed!', 'error'); 262 } 263 }, 264 error: function(xhr, status, error) { 265 syncResult.html('<div class="notice notice-error"><p>Sync failed: ' + error + '</p></div>').show(); 266 PressGaneyReviews.showNotification('Sync failed!', 'error'); 267 }, 268 complete: function() { 269 // Reset button state 270 button.prop('disabled', false); 271 syncText.show(); 272 syncLoading.hide(); 273 } 274 }); 275 }, 276 277 // Escape HTML to prevent XSS 278 escapeHtml: function(text) { 279 var map = { 280 '&': '&', 281 '<': '<', 282 '>': '>', 283 '"': '"', 284 "'": ''' 285 }; 286 return text.replace(/[&<>"']/g, function(m) { return map[m]; }); 287 } 288 }; 289 290 // Initialize when document is ready 291 $(document).ready(function() { 292 PressGaneyReviews.init(); 293 }); 294 295 // Add notification styles 296 $('<style>') 297 .prop('type', 'text/css') 298 .html(` 299 .pressganey-notification { 300 position: fixed; 301 top: 20px; 302 right: 20px; 303 padding: 12px 20px; 304 border-radius: 6px; 305 color: white; 306 font-weight: 500; 307 z-index: 9999; 308 transform: translateX(100%); 309 transition: transform 0.3s ease; 310 max-width: 300px; 311 } 312 .pressganey-notification-success { 313 background: #28a745; 314 } 315 .pressganey-notification-error { 316 background: #dc3545; 317 } 318 .pressganey-notification-show { 319 transform: translateX(0); 320 } 321 `) 322 .appendTo('head'); 323 324})(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.