PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.6.0
Post Views Counter v1.6.0
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / js / column-modal.js
post-views-counter / js Last commit date
admin-dashboard.js 7 months ago admin-post.js 7 months ago admin-quick-edit.js 7 months ago admin-settings.js 7 months ago admin-widgets.js 7 months ago block-editor.min.js 7 months ago column-modal.js 7 months ago counter.js 7 months ago counter.min.js 7 months ago dummy.js 7 months ago frontend.js 7 months ago frontend.min.js 7 months ago
column-modal.js
301 lines
1 /**
2 * Post Views Counter - Column Modal Chart
3 */
4 ( function( $ ) {
5 'use strict';
6
7 // check if jQuery is available
8 if ( typeof $ === 'undefined' )
9 return;
10
11 let pvcModalChart = null;
12 let currentPostId = null;
13
14 // check if localized data is available
15 if ( typeof pvcColumnModal === 'undefined' )
16 return;
17
18 /**
19 * Initialize Micromodal
20 */
21 function initMicromodal() {
22 if ( typeof MicroModal === 'undefined' )
23 return false;
24
25 // initialize with basic config
26 MicroModal.init( {
27 disableScroll: true,
28 awaitCloseAnimation: true
29 } );
30
31 return true;
32 }
33
34 /**
35 * Prepare modal for specific post
36 */
37 function prepareModalForPost( postId, postTitle ) {
38 if ( ! postId )
39 return false;
40
41 currentPostId = postId;
42
43 // set modal title
44 $( '#pvc-modal-title' ).text( postTitle );
45
46 // show loading state
47 const $container = $( '.pvc-modal-chart-container' );
48 $container.addClass( 'loading' );
49 $container.find( '.spinner' ).addClass( 'is-active' );
50
51 // clear previous content
52 $( '.pvc-modal-views-label' ).text( '' );
53 $( '.pvc-modal-count' ).text( '' );
54 $( '.pvc-modal-dates' ).html( '' );
55
56 return true;
57 }
58
59 function resetModalContent() {
60 $( '#pvc-modal-title' ).text( '' );
61 $( '.pvc-modal-views-label' ).text( '' );
62 $( '.pvc-modal-count' ).text( '' );
63 $( '.pvc-modal-dates' ).html( '' );
64
65 const $container = $( '.pvc-modal-chart-container' );
66 $container.removeClass( 'loading' );
67 $container.find( '.spinner' ).removeClass( 'is-active' );
68
69 // remove any error messages
70 $( '.pvc-modal-error' ).remove();
71 }
72
73 /**
74 * Load chart data via AJAX
75 */
76 function loadChartData( postId, period ) {
77 const $container = $( '.pvc-modal-chart-container' );
78
79 // show loading
80 $container.addClass( 'loading' );
81 $container.find( '.spinner' ).addClass( 'is-active' );
82
83 $.ajax( {
84 url: pvcColumnModal.ajaxURL,
85 type: 'POST',
86 dataType: 'json',
87 data: {
88 action: 'pvc_column_chart',
89 nonce: pvcColumnModal.nonce,
90 post_id: postId,
91 period: period
92 },
93 success: function( response ) {
94 if ( response.success ) {
95 renderChart( response.data );
96 } else {
97 showError( response.data.message || pvcColumnModal.i18n.error );
98 }
99 },
100 error: function( xhr, status, error ) {
101 showError( pvcColumnModal.i18n.error );
102 },
103 complete: function() {
104 $container.removeClass( 'loading' );
105 $container.find( '.spinner' ).removeClass( 'is-active' );
106 }
107 } );
108 }
109
110 /**
111 * Render chart with data
112 */
113 function renderChart( data ) {
114 const ctx = document.getElementById( 'pvc-modal-chart' );
115
116 if ( ! ctx )
117 return;
118
119 // destroy existing chart
120 if ( pvcModalChart ) {
121 pvcModalChart.destroy();
122 pvcModalChart = null;
123 }
124
125 // remove any error messages and show canvas
126 $( '.pvc-modal-error' ).remove();
127 $( ctx ).show();
128
129 // update stats
130 $( '.pvc-modal-views-label' ).text( pvcColumnModal.i18n.summary );
131 $( '.pvc-modal-count' ).text( data.total_views.toLocaleString() );
132
133 // update date navigation
134 $( '.pvc-modal-dates' ).html( data.dates_html );
135
136 /* debug logging (admins only) - shows views keys returned from AJAX
137 if ( typeof console !== 'undefined' && data.debug_views_keys ) {
138 console.debug( 'PVC debug: views keys for post ' + data.post_id + ':', data.debug_views_keys );
139 console.debug( 'PVC debug: views sample by keys:', data.debug_views );
140 console.debug( 'PVC debug: example date_key used by client:', data.debug_date_key_example );
141 }
142
143 if ( typeof console !== 'undefined' && data.data ) {
144 console.debug( 'PVC debug: chart data object', data.data );
145 console.debug( 'PVC debug: dataset length', data.data.datasets && data.data.datasets[0] ? data.data.datasets[0].data.length : 0 );
146 }
147 */
148
149 // chart configuration
150 const config = {
151 type: 'line',
152 data: data.data,
153 options: {
154 maintainAspectRatio: false,
155 responsive: true,
156 plugins: {
157 legend: {
158 display: false
159 },
160 tooltip: {
161 callbacks: {
162 title: function( context ) {
163 return data.data.dates[context[0].dataIndex];
164 },
165 label: function( context ) {
166 const count = context.parsed.y;
167 const viewText = count === 1 ? pvcColumnModal.i18n.view : pvcColumnModal.i18n.views;
168 return count.toLocaleString() + ' ' + viewText;
169 }
170 }
171 }
172 },
173 scales: {
174 x: {
175 display: true,
176 grid: {
177 display: false
178 }
179 },
180 y: {
181 display: true,
182 beginAtZero: true,
183 ticks: {
184 precision: 0
185 },
186 grid: {
187 color: 'rgba(0, 0, 0, 0.05)'
188 }
189 }
190 }
191 }
192 };
193
194 // apply design from server
195 if ( data.design ) {
196 config.data.datasets.forEach( function( dataset ) {
197 Object.assign( dataset, data.design );
198 dataset.tension = 0.4; // match dashboard curve
199 } );
200 }
201
202 // create chart
203 pvcModalChart = new Chart( ctx.getContext( '2d' ), config );
204 }
205
206 /**
207 * Show error message without destroying modal structure
208 */
209 function showError( message ) {
210 // destroy existing chart
211 if ( pvcModalChart ) {
212 pvcModalChart.destroy();
213 pvcModalChart = null;
214 }
215
216 // reset states
217 $( '.pvc-modal-summary' ).text( '' );
218 $( '.pvc-modal-dates' ).html( '' );
219
220 const $container = $( '.pvc-modal-chart-container' );
221 $container.removeClass( 'loading' );
222 $container.find( '.spinner' ).removeClass( 'is-active' );
223
224 // remove any existing error message
225 $( '.pvc-modal-error' ).remove();
226
227 // inject error message before chart container
228 $container.before( '<p class="pvc-modal-error">' + message + '</p>' );
229
230 // hide canvas during error
231 $container.find( 'canvas' ).hide();
232 }
233
234 /**
235 * Document ready
236 */
237 $( function() {
238 // check if modal HTML exists
239 if ( $( '#pvc-chart-modal' ).length === 0 )
240 return;
241
242 // initialize Micromodal
243 if ( ! initMicromodal() )
244 return;
245
246 // handle click on view chart link
247 $( document ).on( 'click', '.pvc-view-chart', function( e ) {
248 e.preventDefault();
249
250 const postId = $( this ).data( 'post-id' );
251 const postTitle = $( this ).data( 'post-title' );
252
253 if ( ! postId )
254 return;
255
256 // prepare modal with post data
257 if ( prepareModalForPost( postId, postTitle ) ) {
258 // open modal using MicroModal with callbacks
259 if ( typeof MicroModal !== 'undefined' ) {
260 MicroModal.show( 'pvc-chart-modal', {
261 onShow: function( modal ) {
262 if ( currentPostId )
263 loadChartData( currentPostId, '' );
264 },
265 onClose: function() {
266 // destroy chart when modal closes
267 if ( pvcModalChart ) {
268 pvcModalChart.destroy();
269 pvcModalChart = null;
270 }
271
272 currentPostId = null;
273
274 // reset modal content
275 resetModalContent();
276 },
277 disableScroll: true,
278 awaitCloseAnimation: true
279 } );
280 }
281 }
282 } );
283
284 // handle period navigation
285 $( document ).on( 'click', '.pvc-modal-nav-prev, .pvc-modal-nav-next', function( e ) {
286 e.preventDefault();
287
288 // check if disabled
289 if ( $( this ).hasClass( 'pvc-disabled' ) )
290 return;
291
292 const period = $( this ).data( 'period' );
293
294 if ( period && currentPostId ) {
295 loadChartData( currentPostId, period );
296 }
297 } );
298 } );
299
300 } )( jQuery );
301