diff --git a/js/simpleads.charts.js b/js/simpleads.charts.js --- charts.truly_orig.js 2026-03-27 09:46:22.899714548 +0100 +++ charts.current.js 2026-03-27 09:45:25.755043378 +0100 @@ -43,7 +43,7 @@ chartConfig.data.datasets = []; var aggregated = []; for (var i = 0; i < data.length; i++) { - var sDate = data[i].month + ' ' + data[i].year; + var sDate = data[i].year + '. ' + data[i].month; if (chartConfig.data.labels.indexOf(sDate) === -1) { chartConfig.data.labels.push(sDate); } @@ -68,19 +68,51 @@ var chartConfig = getLineChartOptions(this.Drupal.t('Days'), this.Drupal.t('Values')); chartConfig.data.labels = []; chartConfig.data.datasets = []; - var aggregated = []; - for (var i = 0; i < data.length; i++) { - var sDate = data[i].date; - if (limit > i) { + + var aggregated = {}; + + if (!data || !data.length) { + renderLineChart(element, chartConfig, aggregated); + return; + } + + limit = parseInt(limit, 10) || 0; + if (limit <= 0) { + renderLineChart(element, chartConfig, aggregated); + return; + } + + var firstDate = new Date(data[0].date); + var lastDate = new Date(data[data.length - 1].date); + var newestFirst = firstDate > lastDate; + + if (newestFirst) { + for (var i = 0; i < Math.min(limit, data.length); i++) { + var sDate = data[i].date; chartConfig.data.labels.push(sDate); + aggregated[sDate] = { + clicks: parseInt(data[i].clicks, 10) || 0, + clicks_unique: parseInt(data[i].clicks_unique, 10) || 0, + impressions: parseInt(data[i].impressions, 10) || 0, + impressions_unique: parseInt(data[i].impressions_unique, 10) || 0, + ctr: parseFloat(data[i].ctr) || 0 + }; + } + } else { + var start = Math.max(data.length - limit, 0); + for (var j = start; j < data.length; j++) { + var sDate2 = data[j].date; + chartConfig.data.labels.push(sDate2); + aggregated[sDate2] = { + clicks: parseInt(data[j].clicks, 10) || 0, + clicks_unique: parseInt(data[j].clicks_unique, 10) || 0, + impressions: parseInt(data[j].impressions, 10) || 0, + impressions_unique: parseInt(data[j].impressions_unique, 10) || 0, + ctr: parseFloat(data[j].ctr) || 0 + }; } - aggregated[sDate] = []; - aggregated[sDate]['clicks'] = parseInt(data[i].clicks); - aggregated[sDate]['clicks_unique'] = parseInt(data[i].clicks_unique); - aggregated[sDate]['impressions'] = parseInt(data[i].impressions); - aggregated[sDate]['impressions_unique'] = parseInt(data[i].impressions_unique); - aggregated[sDate]['ctr'] = parseFloat(data[i].ctr); } + renderLineChart(element, chartConfig, aggregated); }; @@ -93,8 +125,10 @@ backgroundColor: [chartColors.clicks, chartColors.clicks_unique, chartColors.ctr], label: '' }], - labels: [chartLabels.clicks_unique, chartLabels.clicks, chartLabels.ctr] + labels: [chartLabels.clicks_unique, chartLabels.clicks, this.Drupal.t('Ratio')] }); + var existingClicks = Chart.getChart(ctxClicks); + if (existingClicks) { existingClicks.destroy(); } new Chart(ctxClicks, chartConfig); } else { @@ -108,8 +142,10 @@ backgroundColor: [chartColors.impressions, chartColors.impressions_unique, chartColors.ctr], label: '' }], - labels: [chartLabels.impressions_unique, chartLabels.impressions, chartLabels.ctr] + labels: [chartLabels.impressions_unique, chartLabels.impressions, this.Drupal.t('Ratio')] }); + var existingImpressions = Chart.getChart(ctxImpressions); + if (existingImpressions) { existingImpressions.destroy(); } new Chart(ctxImpressions, chartConfig); } else { @@ -118,6 +154,7 @@ }; SimpleAdsCharts.prototype.table = function(element, data) { + data.reverse(); var arrayData = []; var arrayCsvData = []; var arrayTitles = [ @@ -126,20 +163,20 @@ {title: this.Drupal.t('Unique clicks')}, {title: this.Drupal.t('Impressions')}, {title: this.Drupal.t('Unique impressions')}, - {title: this.Drupal.t('CTR')} + {title: 'CTR'} ]; for (var key of Object.keys(data)) { arrayData.push(new Array( data[key].date, data[key].clicks, data[key].clicks_unique, data[key].impressions, data[key].impressions_unique, - data[key].ctr + '%' + data[key].ctr*100 + '%' )); arrayCsvData.push(new Array( '"' + data[key].date + '"', data[key].clicks, data[key].clicks_unique, data[key].impressions, data[key].impressions_unique, - data[key].ctr + '%' + data[key].ctr*100 + '%' )); } element.DataTable({ @@ -259,6 +296,8 @@ }); var ctx = element.getContext('2d'); + var existingChart = Chart.getChart(ctx); + if (existingChart) { existingChart.destroy(); } new Chart(ctx, chartsConfig); }; @@ -285,20 +324,20 @@ intersect: true }, scales: { - xAxes: [{ + x: { display: true, scaleLabel: { display: true, labelString: xAxesLabel } - }], - yAxes: [{ + }, + y: { display: true, scaleLabel: { display: true, labelString: yAxesLabel } - }] + } } } }; diff --git a/src/SimpleAdsStats.php b/src/SimpleAdsStats.php index 8989075..4134fb1 100644 --- a/src/SimpleAdsStats.php +++ b/src/SimpleAdsStats.php @@ -7,6 +7,8 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\simpleads\Form\BaseSettingsForm; use Drupal\Core\Datetime\Entity\DateFormat; +use Drupal\Core\Datetime\DrupalDateTime; + /** * SimpleAdsStats module helper. @@ -83,9 +85,9 @@ class SimpleAdsStats { ->orderBy('s.date', 'DESC') ->execute(); foreach ($result as $row) { - $date = \DateTime::createFromFormat('Ymd', $row->date); + $date = DrupalDateTime::createFromFormat('Ymd', $row->date); $stats[] = [ - 'date' => $date->format($this->getDateTimeFormat()), + 'date' => $date->format($this->getDateTimeFormat(), ['langcode' => \Drupal::languageManager()->getCurrentLanguage()->getId()]), 'clicks' => $row->clicks, 'impressions' => $row->impressions, 'clicks_unique' => $row->clicks_unique, @@ -126,15 +128,6 @@ class SimpleAdsStats { public function loadData() { $stats = []; if ($entity_id = $this->getEntityId()) { - // Todays stats. - if ($today_stats = $this->loadTodayData()) { - $date = \DateTime::createFromFormat('YMd', date('YMd')); - $today_stats['month'] = $date->format('F'); - $today_stats['day'] = $date->format('d'); - $today_stats['year'] = $date->format('Y'); - $today_stats['weekday'] = $date->format('w'); - $stats[] = $today_stats; - } $result = $this->connection->query('SELECT DATE_FORMAT(FROM_UNIXTIME(timestamp), \'%M\') AS "month", DATE_FORMAT(FROM_UNIXTIME(timestamp), \'%d\') AS "day", @@ -148,10 +141,10 @@ class SimpleAdsStats { GROUP BY DATE_FORMAT(FROM_UNIXTIME(timestamp), \'%M, %Y\'), timestamp ORDER BY timestamp', ['entity_id' => $entity_id]); foreach ($result as $row) { - $date = \DateTime::createFromFormat('YMd', $row->year . $row->month . $row->day); + $date = DrupalDateTime::createFromFormat('YFd', $row->year . $row->month . $row->day); $stats[] = [ - 'date' => $date->format($this->getDateTimeFormat()), - 'month' => $this->t('@month', ['@month' => $date->format('F')]), + 'date' => $date->format($this->getDateTimeFormat(), ['langcode' => \Drupal::languageManager()->getCurrentLanguage()->getId()]), + 'month' => $this->t($date->format('F')), 'day' => $date->format('d'), 'year' => $date->format('Y'), 'weekday' => $date->format('w'), @@ -162,6 +155,15 @@ class SimpleAdsStats { 'ctr' => number_format($row->clicks_unique / $row->impressions_unique, 4, '.', '') ]; } + // Todays stats. + if ($today_stats = $this->loadTodayData()) { + $date = \DateTime::createFromFormat('YMd', date('YMd')); + $today_stats['month'] = t($date->format('F')); + $today_stats['day'] = $date->format('d'); + $today_stats['year'] = $date->format('Y'); + $today_stats['weekday'] = $date->format('w'); + $stats[] = $today_stats; + } } return $stats; } @@ -213,7 +215,7 @@ class SimpleAdsStats { */ public function getTodaysUniqueClicks() { $stat = $this->connection->query("SELECT COUNT(DISTINCT s.ip_address) AS unique_count - FROM {simpleads_impressions} s + FROM {simpleads_clicks} s WHERE s.entity_id = :id GROUP BY FROM_UNIXTIME(s.timestamp, '%Y%m%d'), s.entity_id", [':id' => $this->getEntityId()])->fetchObject(); return (int) $stat->unique_count; diff --git a/js/datatables/datatables.min.js b/js/datatables/datatables.min.js --- a/js/datatables/datatables.min.js +++ b/js/datatables/datatables.min.js @@ -10,6 +10,9 @@ * DataTables 1.10.18 */ +// jQuery 4 compatibility: jQuery.isArray was removed in jQuery 4. +if (typeof jQuery !== 'undefined' && !jQuery.isArray) { jQuery.isArray = Array.isArray; } + /*! DataTables 1.10.18 ©2008-2018 SpryMedia Ltd - datatables.net/license diff --git a/js/simpleads.block.js b/js/simpleads.block.js --- a/js/simpleads.block.js +++ b/js/simpleads.block.js @@ -27,14 +27,14 @@ $el.html(lib.getAdsHtml('slider', data)); var slider = $el.find('.simpleads-slider'); slider.slick(rotationOptions); - var initialEntityId = slider.find('li a').first().data('id'); + var initialEntityId = slider.find('li [data-id]').first().data('id'); lib.trackImpression(initialEntityId); if (countImpressionsOnce === true) { shownAds[groupId + ':' + initialEntityId] = true; } slider.on('afterChange', function(e, slick, currentSlide, nextSlide) { - var entityId = $(slick.$slides[currentSlide]).find('a').data('id'); + var entityId = $(slick.$slides[currentSlide]).find('[data-id]').data('id'); // Track impression. if (countImpressionsOnce === true) { if (shownAds[groupId + ':' + entityId] === undefined) { @@ -54,14 +54,14 @@ } else if (rotationType == 'multiple') { $el.html(lib.getRandomAdsHtml(data, multipleRandomLimit)); - var ad = $el.find('.simpleads-multiple-random a'); + var ad = $el.find('.simpleads-multiple-random [data-id]'); lib.trackImpression(ad.data('id')); lib.clickAd(ad, function() {}); } else { // Random $el.html(lib.getAdsHtml('default', data)); - var ad = $el.find('.simpleads-random a'); + var ad = $el.find('.simpleads-random [data-id]'); lib.trackImpression(ad.data('id')); lib.clickAd(ad, function() { if ($.modal.isActive()) {