PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.8.5
Independent Analytics – WordPress Analytics Plugin v2.8.5
2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / javascript-source / controllers / report_controller.js
independent-analytics / javascript-source / controllers Last commit date
campaign_builder_controller.js 2 years ago chart_controller.js 1 year ago chart_geo_controller.js 2 years ago chart_interval_controller.js 2 years ago clipboard_controller.js 2 years ago copy_report_controller.js 2 years ago create_report_controller.js 2 years ago delete_data_controller.js 2 years ago delete_report_controller.js 2 years ago easepick_controller.js 2 years ago export_reports_controller.js 2 years ago filters_controller.js 1 year ago group_controller.js 2 years ago import_reports_controller.js 2 years ago migration_redirect_controller.js 2 years ago modal_controller.js 2 years ago plugin_group_options_controller.js 1 year ago pruner_controller.js 1 year ago quick_stats_controller.js 2 years ago real_time_controller.js 2 years ago rename_report_controller.js 2 years ago report_controller.js 1 year ago reset_analytics_controller.js 2 years ago save_report_controller.js 2 years ago select_input_controller.js 2 years ago set_favorite_report_controller.js 2 years ago sort_controller.js 2 years ago sortable_reports_controller.js 2 years ago table_columns_controller.js 2 years ago woocommerce_settings_controller.js 1 year ago
report_controller.js
428 lines
1 import {Controller} from "@hotwired/stimulus"
2 import {downloadCSV} from '../download'
3 import html2pdf from 'html2pdf.js';
4
5 class Report_Controller extends Controller {
6 /**
7 * Store the jQuery request so that it can be canceled if a new report is requested before the
8 * current one is fetched.
9 */
10 static request;
11 static targets = ['loadMore', 'exportCSV', 'exportPDF', 'spinner']
12 static values = {
13 name: String,
14 relativeRangeId: String,
15 exactStart: String,
16 exactEnd: String,
17 group: String,
18 chartInterval: String,
19 sortColumn: String,
20 sortDirection: String,
21 columns: Array,
22 quickStats: Array,
23 primaryChartMetricId: String,
24 secondaryChartMetricId: String,
25 filters: Array
26 }
27
28 exactStart = undefined
29 exactEnd = undefined
30 relativeRangeId = undefined
31 columns = undefined
32 quickStats = undefined
33 filters = []
34 sortColumn = undefined
35 sortDirection = undefined
36 group = undefined
37 chartInterval = undefined
38 primaryChartMetricId = undefined
39 secondaryChartMetricId = undefined
40 page = 1
41
42 connect() {
43 // If any values are empty strings, set them equal to undefined instead
44 this.exactStart = this.exactStartValue === "" ? undefined : this.exactStartValue;
45 this.exactEnd = this.exactEndValue === "" ? undefined : this.exactEndValue;
46 this.relativeRangeId = this.relativeRangeIdValue === "" ? undefined : this.relativeRangeIdValue
47 this.columns = this.columnsValue
48 this.quickStats = this.quickStatsValue
49 this.group = this.groupValue
50 this.chartInterval = this.chartIntervalValue
51 this.sortColumn = this.sortColumnValue
52 this.sortDirection = this.sortDirectionValue
53 this.primaryChartMetricId = this.primaryChartMetricIdValue
54 this.secondaryChartMetricId = this.secondaryChartMetricIdValue
55 this.filters = this.filtersValue
56 document.addEventListener('iawp:changeDates', this.datesChanged)
57 document.addEventListener('iawp:changeColumns', this.columnsChanged)
58 document.addEventListener('iawp:changeQuickStats', this.quickStatsChanged)
59 document.addEventListener('iawp:changeFilters', this.filtersChanged)
60 document.addEventListener('iawp:changeSort', this.sortChanged)
61 document.addEventListener('iawp:changeGroup', this.changeGroup)
62 document.addEventListener('iawp:changeChartInterval', this.changeChartInterval)
63 document.addEventListener('iawp:changePrimaryChartMetric', this.changePrimaryChartMetric)
64 document.addEventListener('iawp:changeSecondaryChartMetric', this.changeSecondaryChartMetric)
65 document.addEventListener('iawp:fetchingReport', this.onFetchingReport)
66 setTimeout(() => {
67 this.fetch({
68 tableOnly: this.filters.length === 0,
69 showLoadingOverlay: false
70 })
71 }, 0)
72 }
73
74 disconnect() {
75 document.removeEventListener('iawp:changeDates', this.datesChanged)
76 document.removeEventListener('iawp:changeColumns', this.columnsChanged)
77 document.removeEventListener('iawp:changeQuickStats', this.quickStatsChanged)
78 document.removeEventListener('iawp:changeFilters', this.filtersChanged)
79 document.removeEventListener('iawp:changeSort', this.sortChanged)
80 document.removeEventListener('iawp:changeGroup', this.changeGroup)
81 document.removeEventListener('iawp:changeChartInterval', this.changeChartInterval)
82 document.removeEventListener('iawp:changePrimaryChartMetric', this.changePrimaryChartMetric)
83 document.removeEventListener('iawp:changeSecondaryChartMetric', this.changeSecondaryChartMetric)
84 document.removeEventListener('iawp:fetchingReport', this.onFetchingReport)
85 }
86
87 emitChangedOption(detail) {
88 document.dispatchEvent(
89 new CustomEvent('iawp:changedOption', {
90 detail
91 })
92 )
93 }
94
95 changePrimaryChartMetric = (e) => {
96 this.primaryChartMetricId = e.detail.primaryChartMetricId
97 this.emitChangedOption({
98 'primary_chart_metric_id': this.primaryChartMetricId
99 })
100 }
101
102 changeSecondaryChartMetric = (e) => {
103 this.secondaryChartMetricId = e.detail.secondaryChartMetricId
104 this.emitChangedOption({
105 'secondary_chart_metric_id': this.secondaryChartMetricId
106 })
107 }
108
109 datesChanged = (e) => {
110 this.exactStart = e.detail.exactStart
111 this.exactEnd = e.detail.exactEnd
112 this.relativeRangeId = e.detail.relativeRangeId
113 this.page = 1;
114
115 this.emitChangedOption({
116 'exact_start': this.exactStart || null,
117 'exact_end': this.exactEnd || null,
118 'relative_range_id': this.relativeRangeId || null
119 })
120 this.fetch({newDateRange: true})
121 }
122
123 columnsChanged = (e) => {
124 this.columns = e.detail.optionIds
125 this.emitChangedOption({
126 'columns': this.columns
127 })
128 }
129
130 quickStatsChanged = (e) => {
131 this.quickStats = e.detail.optionIds
132 this.emitChangedOption({
133 'quick_stats': this.quickStats
134 })
135 }
136
137 filtersChanged = (e) => {
138 this.filters = e.detail.filters
139 this.page = 1;
140
141 this.emitChangedOption({
142 'filters': this.filters
143 })
144 this.fetch({showLoadingOverlay: e.detail.showLoadingOverlay})
145 }
146
147 sortChanged = (e) => {
148 this.sortColumn = e.detail.sortColumn
149 this.sortDirection = e.detail.sortDirection
150 this.page = 1;
151
152 this.emitChangedOption({
153 'sort_column': this.sortColumn,
154 'sort_direction': this.sortDirection
155 })
156 this.fetch({tableOnly: true})
157 }
158
159 changeGroup = (e) => {
160 if (this.group === e.detail.group) {
161 return;
162 }
163
164 this.group = e.detail.group
165 this.page = 1
166 this.emitChangedOption({
167 'group_name': this.group
168 })
169 this.fetch({newGroup: true});
170 }
171
172 changeChartInterval = (e) => {
173 const chartInterval = e.detail.chartInterval
174
175 if (this.chartInterval === chartInterval) {
176 return;
177 }
178
179 this.chartInterval = chartInterval
180 this.emitChangedOption({
181 'chart_interval': this.chartInterval
182 })
183 this.fetch();
184 }
185
186 onFetchingReport = () => {
187 this.spinnerTarget.classList.remove('hidden')
188
189 document.addEventListener('iawp:fetchedReport', () => {
190 this.spinnerTarget.classList.add('hidden')
191 }, {once: true})
192 }
193
194 loadMore = () => {
195 this.page = this.page + 1
196
197 this.fetch({tableOnly: true})
198 }
199
200 fetch({
201 tableOnly = false,
202 showLoadingOverlay = true,
203 newGroup = false,
204 newDateRange = false
205 } = {}) {
206
207 if (showLoadingOverlay) {
208 jQuery('#iawp-parent').addClass('loading');
209 }
210
211 const data = {
212 ...iawpActions.filter,
213 'filters': this.filters,
214 'exact_start': this.exactStart,
215 'exact_end': this.exactEnd,
216 'is_new_date_range': newDateRange,
217 'relative_range_id': this.relativeRangeId,
218 'table_type': jQuery('#data-table').data('table-name'),
219 'columns': this.columns,
220 'report_quick_stats': ['visitors'], // TODO
221 'primary_chart_metric_id': this.primaryChartMetricId,
222 'secondary_chart_metric_id': this.secondaryChartMetricId,
223 'sort_column': this.sortColumn,
224 'quick_stats': this.quickStats,
225 'sort_direction': this.sortDirection,
226 'group': this.group,
227 'is_new_group': newGroup,
228 'chart_interval': this.chartInterval,
229 'page': this.page,
230 };
231
232 if (Report_Controller.request) {
233 Report_Controller.request.abort();
234 }
235
236 document.dispatchEvent(
237 new CustomEvent('iawp:fetchingReport')
238 )
239
240 Report_Controller.request = jQuery.post(ajaxurl, data, (response) => {
241 response = response.data
242
243 this.columns = response.columns
244 this.filters = response.filters
245 this.chartInterval = response.chartInterval
246
247 jQuery('#iawp-columns .row-number').text(response.totalNumberOfRows.toLocaleString());
248 document.getElementById('data-table').setAttribute('data-total-number-of-rows', response.totalNumberOfRows)
249 document.dispatchEvent(
250 new CustomEvent('iawp:fetchedReport')
251 )
252
253 if (newGroup) {
254 jQuery('#iawp-table-wrapper').replaceWith(response.table)
255 jQuery('[data-plugin-group-options-option-type-value=columns]').replaceWith(response.columnsHTML)
256
257 document.dispatchEvent(
258 new CustomEvent('iawp:changeColumns', {
259 detail: {
260 optionIds: this.columns
261 }
262 })
263 )
264 } else {
265 jQuery('#iawp-rows').replaceWith(response.rows);
266 }
267
268 if (!tableOnly) {
269 jQuery('#dates-button span:last-child').text(response.label)
270 jQuery('#independent-analytics-chart').closest('.chart-container').replaceWith(response.chart);
271 jQuery('#quick-stats').replaceWith(response.stats);
272 }
273
274 document.dispatchEvent(
275 new CustomEvent('iawp:updateColumnsUserInterface')
276 )
277
278 document.dispatchEvent(
279 new CustomEvent('iawp:groupChanged', {
280 detail: {
281 groupId: response.groupId
282 }
283 })
284 )
285
286 document.dispatchEvent(
287 new CustomEvent('iawp:filtersChanged', {
288 detail: {
289 filtersTemplateHTML: response.filtersTemplateHTML,
290 filtersButtonsHTML: response.filtersButtonsHTML,
291 filters: response.filters
292 }
293 })
294 )
295
296 this.exportPDFTarget.removeAttribute('disabled')
297
298 if (response.isLastPage) {
299 this.loadMoreTarget.setAttribute('disabled', 'disabled')
300 } else {
301 this.loadMoreTarget.removeAttribute('disabled')
302 }
303
304 jQuery('#iawp-parent').removeClass('loading');
305 });
306 }
307
308 exportCSV() {
309 const data = {
310 ...iawpActions.filter,
311 'filters': this.filters,
312 'exact_start': this.exactStart,
313 'exact_end': this.exactEnd,
314 'is_new_date_range': false,
315 'relative_range_id': this.relativeRangeId,
316 'table_type': jQuery('#data-table').data('table-name'),
317 'columns': this.columns,
318 'primary_chart_metric_id': this.primaryChartMetricId,
319 'secondary_chart_metric_id': this.secondaryChartMetricId,
320 'sort_column': this.sortColumn,
321 'quick_stats': this.quickStats,
322 'sort_direction': this.sortDirection,
323 'group': this.group,
324 'is_new_group': false,
325 'chart_interval': this.chartInterval,
326 'page': this.page,
327 'as_csv': true
328 };
329
330 this.exportCSVTarget.classList.add('sending')
331 this.exportCSVTarget.setAttribute('disabled', 'disabled')
332
333 if (Report_Controller.csvRequest) {
334 Report_Controller.csvRequest.abort();
335 }
336
337 Report_Controller.csvRequest = jQuery.post(ajaxurl, data, (response) => {
338 downloadCSV(this.getFileName('csv'), response)
339 this.exportCSVTarget.classList.add('sent')
340 this.exportCSVTarget.classList.remove('sending')
341 this.exportCSVTarget.removeAttribute('disabled')
342
343 setTimeout(() => {
344 this.exportCSVTarget.classList.remove('sent')
345 }, 1000)
346 })
347 }
348
349 exportPDF() {
350 this.exportPDFTarget.classList.add('sending')
351 this.exportPDFTarget.setAttribute('disabled', 'disabled')
352
353 setTimeout(() => {
354 const element = document.getElementById('wpwrap').cloneNode(true)
355 const options = {
356 filename: this.getFileName('pdf'),
357 jsPDF: {
358 unit: 'in',
359 format: 'letter',
360 orientation: 'landscape'
361 },
362 html2canvas: {
363 windowWidth: 1280
364 }
365 }
366 let base64Image = null
367
368 if (window.iawp_chart) {
369 const chartImageWidth = 1080
370 const chartImageHeight = chartImageWidth * .25
371 window.iawp_chart.resize(chartImageWidth, chartImageHeight)
372 base64Image = window.iawp_chart.toBase64Image('image/png', 1);
373 window.iawp_chart.resize()
374 }
375
376 if(window.iawp_geo_chart) {
377 base64Image = window.iawp_geo_chart.getImageURI()
378 }
379
380 if(base64Image) {
381 const imageElement = document.createElement('img')
382 imageElement.src = base64Image
383
384 element.querySelector('#independent-analytics-chart').replaceWith(imageElement)
385 }
386
387 // Prevent stimulus controllers from firing
388 element.querySelectorAll('[data-controller]').forEach((element) => {
389 element.removeAttribute('data-controller')
390 })
391
392 // Preserve selected values in clone by manually adding "selected" to options
393 element.querySelectorAll('select').forEach((element) => {
394 if(!element.id) {
395 return
396 }
397
398 const originalValue = document.getElementById(element.id).value
399
400 element.options.forEach((option) => {
401 option.toggleAttribute('selected', option.value === originalValue)
402 })
403 })
404
405 html2pdf().set(options).from(element).toContainer().save().then(() => {
406 this.exportPDFTarget.classList.add('sent')
407 this.exportPDFTarget.classList.remove('sending')
408 this.exportPDFTarget.removeAttribute('disabled')
409
410 setTimeout(() => {
411 this.exportPDFTarget.classList.remove('sent')
412 }, 1000)
413 })
414 }, 250) // Allow animations to finish before exporting blocks things up
415 }
416
417 getFileName(fileExtension) {
418 const reportTitleElement = document.querySelector('#report-title-bar .report-title')
419
420 if (!reportTitleElement) {
421 return 'report.' + fileExtension
422 }
423
424 return reportTitleElement.innerText.replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase() + '.' + fileExtension
425 }
426 }
427
428 export default Report_Controller;