1// Ajax counter â post views 2// Loaded by vt-post-views.php (VT_PLUGIN_URL/js/post-views.js) 3// Requires <body data-post-id="<?php echo get_the_ID(); ?>"> in your theme. 4 5jQuery(document).ready(function($) { 6 7 function trackPostView(postId) { 8 $.ajax({ 9 url: postViewsAjax.ajax_url, 10 type: 'POST', 11 data: { 12 action: 'wpb_track_post_views', 13 post_id: postId, 14 nonce: postViewsAjax.nonce 15 }, 16 success: function(response) { 17 if (response.success) { 18 $('.post-views-count').text(response.data.count); 19 } 20 } 21 }); 22 } 23 24 function getPostViews(postId, element) { 25 $.ajax({ 26 url: postViewsAjax.ajax_url, 27 type: 'POST', 28 data: { 29 action: 'wpb_get_post_views', 30 post_id: postId, 31 nonce: postViewsAjax.nonce 32 }, 33 success: function(response) { 34 if (response.success) { 35 $(element).text(response.data.count); 36 } 37 } 38 }); 39 } 40 41 if (typeof postViewsAjax !== 'undefined') { 42 var postId = $('body').data('post-id'); 43 if (postId) { 44 trackPostView(postId); 45 } 46 } 47 48 // ----------------------------------------------------------------------- 49 // Post audience evolution chart (admin article-stats page only) 50 // ----------------------------------------------------------------------- 51 52 if ($('#post_audience_select').length === 0) { 53 return; // Not on the article-stats page, stop here 54 } 55 56 var postAudienceChartInstance = null; 57 58 function updatePostAudienceChart(postId, range) { 59 $('#post-audience-loading').show(); 60 $('#post-audience-chart-wrap').hide(); 61 $('#post-audience-empty').hide(); 62 63 $.ajax({ 64 url: ajaxurl, 65 method: 'GET', 66 data: { 67 action: 'vt_fetch_post_audience_data', 68 post_id: postId, 69 range: range, 70 nonce: vtNonce 71 }, 72 success: function(response) { 73 $('#post-audience-loading').hide(); 74 75 if (!response.success || !response.data.dates || response.data.dates.length === 0) { 76 $('#post-audience-empty').show(); 77 return; 78 } 79 80 var data = response.data; 81 var totalFormatted = data.total_views ? data.total_views.toLocaleString('fr-FR') + ' vues au total' : ''; 82 $('#post-audience-title').html( 83 data.title + 84 ( totalFormatted ? ' <span style="font-weight:normal; color:#888; font-size:.9em;">(' + totalFormatted + ')</span>' : '' ) 85 ); 86 87 if (postAudienceChartInstance) { 88 postAudienceChartInstance.destroy(); 89 } 90 91 var canvas = document.getElementById('postAudienceChart'); 92 canvas.style.height = '280px'; 93 canvas.style.width = '100%'; 94 canvas.height = 280; 95 canvas.width = canvas.offsetWidth; 96 97 var ctx = canvas.getContext('2d'); 98 postAudienceChartInstance = new Chart(ctx, { 99 type: 'line', 100 data: { 101 labels: data.dates, 102 datasets: [{ 103 label: 'Vues par jour', 104 data: data.views, 105 borderColor: 'rgba(75, 192, 192, 1)', 106 backgroundColor: 'rgba(75, 192, 192, 0.2)', 107 borderWidth: 1, 108 tension: 0.1 109 }] 110 }, 111 options: { 112 responsive: true, 113 maintainAspectRatio: false, 114 animation: false, 115 plugins: { 116 tooltip: { 117 enabled: true, 118 mode: 'index', 119 intersect: false 120 } 121 }, 122 scales: { 123 x: { title: { display: true, text: 'Date' } }, 124 y: { beginAtZero: true, title: { display: true, text: 'Vues' } } 125 } 126 } 127 }); 128
129 $('#post-audience-chart-wrap').show(); 130 }, 131 error: function() { 132 $('#post-audience-loading').hide(); 133 $('#post-audience-empty').show(); 134 } 135 }); 136 } 137 138 // Search posts by title â show results as clickable list below input 139 var searchTimer = null; 140 var $searchInput = $('#post_audience_search'); 141 var $searchResults = $('#post-audience-search-results'); 142 var $searchLoading = $('#post-audience-search-loading'); 143 144 $searchInput.on('input', function() { 145 var term = $(this).val().trim(); 146 clearTimeout(searchTimer); 147 $searchResults.hide().empty(); 148 149 if (term.length < 3) return; 150 151 searchTimer = setTimeout(function() { 152 $searchLoading.show(); 153 $.ajax({ 154 url: ajaxurl, 155 method: 'GET', 156 data: { action: 'vt_search_posts_by_title', term: term, nonce: vtNonce }, 157 success: function(response) { 158 $searchLoading.hide(); 159 $searchResults.empty(); 160 161 if (!response.success || !response.data.length) { 162 $searchResults.append('<div style="padding:8px 12px; color:#888; font-size:.9em;">Aucun résultat.</div>'); 163 $searchResults.show(); 164 return; 165 } 166 167 $.each(response.data, function(i, post) { 168 var decoded = $('<textarea>').html(post.label).val(); 169 $('<div>') 170 .text(decoded) 171 .css({ padding: '8px 12px', cursor: 'pointer', fontSize: '.9em', borderBottom: '1px solid #f0f0f0' }) 172 .on('mouseenter', function() { $(this).css('background', '#f0f6fc'); }) 173 .on('mouseleave', function() { $(this).css('background', '#fff'); }) 174 .on('click', function() { 175 $searchInput.val(decoded); 176 $searchResults.hide().empty(); 177 // Sync the dropdown selection too 178 $('#post_audience_select').val(post.id); 179 // Trigger chart 180 $('#post-audience-ranges').show(); 181 $('.post-audience-range').removeClass('active'); 182 $('.post-audience-range[data-range="7"]').addClass('active'); 183 updatePostAudienceChart(post.id, 7); 184 }) 185 .appendTo($searchResults); 186 }); 187 188 $searchResults.show(); 189 }, 190 error: function() { $searchLoading.hide(); } 191 }); 192 }, 400); 193 }); 194 195 // Close results when clicking outside 196 $(document).on('click', function(e) { 197 if (!$(e.target).closest('#post_audience_search, #post-audience-search-results').length) { 198 $searchResults.hide(); 199 } 200 }); 201 202 // Load more posts into the dropdown 203 $('#post-audience-load-more').on('click', function(e) { 204 e.preventDefault(); 205 var $link = $(this); 206 var page = parseInt($link.data('page'), 10); 207 208 $('#post-audience-load-more-loading').show(); 209 $link.hide(); 210 211 $.ajax({ 212 url: ajaxurl, 213 method: 'GET', 214 data: { 215 action: 'vt_load_more_posts_for_select', 216 page: page, 217 nonce: vtNonce 218 }, 219 success: function(response) { 220 $('#post-audience-load-more-loading').hide(); 221 if (!response.success) return; 222 223 var $select = $('#post_audience_select'); 224 $.each(response.data.posts, function(i, post) { 225 $('<option>').val(post.id).text(post.label).appendTo($select); 226 }); 227 228 if (response.data.hasMore) { 229 $link.data('page', page + 1).show(); 230 } else { 231 $('#post-audience-load-more-done').show(); 232 } 233 }, 234 error: function() { 235 $('#post-audience-load-more-loading').hide(); 236 $link.show(); 237 } 238 }); 239 }); 240 241 // Show range links on post selection and trigger default 7-day chart 242 $('#post_audience_select').on('change', function() { 243 var postId = $(this).val(); 244 if (postId) { 245 $('#post-audience-ranges').show(); 246 $('.post-audience-range').removeClass('active'); 247 $('.post-audience-range[data-range="7"]').addClass('active'); 248 updatePostAudienceChart(postId, 7); 249 } else { 250 $('#post-audience-ranges').hide();
251 $('#post-audience-chart-wrap').hide(); 252 $('#post-audience-empty').hide(); 253 } 254 }); 255 256 // Range link clicks 257 // "Depuis la publication" n'est pas un nombre de jours : on transmet la 258 // valeur telle quelle (le back-end sait interpréter "publication"). 259 $('.post-audience-range').on('click', function(e) { 260 e.preventDefault(); 261 var postId = $('#post_audience_select').val(); 262 if (!postId) return; 263 $('.post-audience-range').removeClass('active'); 264 $(this).addClass('active'); 265 266 var rawRange = $(this).data('range'); 267 var range = ( 'publication' === String(rawRange) ) ? 'publication' : parseInt(rawRange, 10); 268 updatePostAudienceChart(postId, range); 269 }); 270 271});
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.