Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chart to ?action=info #144

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
"ext.matomoanalytics.graphs": {
"scripts": "ext.matomoanalytics.graphs.js"
},
"ext.matomoanalytics.infochart": {
"scripts": "ext.matomoanalytics.infochart.js",
"dependencies": "oojs-ui"
},
"ext.matomoanalytics.infopage": {
"styles": "ext.matomoanalytics.infopage.less"
},
"ext.matomoanalytics.special": {
"styles": "ext.matomoanalytics.special.less"
}
Expand Down
18 changes: 10 additions & 8 deletions includes/HookHandlers/Main.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Miraheze\MatomoAnalytics\HookHandlers;

use MediaWiki\Context\IContextSource;
use MediaWiki\Hook\InfoActionHook;
use MediaWiki\Hook\SkinAfterBottomScriptsHook;
use MediaWiki\Html\Html;
Expand Down Expand Up @@ -85,22 +84,25 @@ public function onSkinAfterBottomScripts( $skin, &$text ) {
return true;
}

/**
* Display total pageviews in the last 30 days and show a graph with details when clicked.
* @param IContextSource $context
* @param array &$pageInfo
*/
public function onInfoAction( $context, &$pageInfo ) {
$mA = new MatomoAnalyticsWiki( $context->getConfig()->get( MainConfigNames::DBname ) );

$context->getOutput()->addModules( [ 'ext.matomoanalytics.charts', 'ext.matomoanalytics.infochart' ] );
$context->getOutput()->addModuleStyles( [ 'ext.matomoanalytics.infopage' ] );

$title = $context->getTitle();
$url = $title->getFullURL();
$data = $mA->getPageViews( $url );
$total = array_sum( $data );
$data = $mA->getPageViews( $url, 'day' );
$total = array_sum( array_filter( $data, 'is_numeric' ) );

$pageInfo['header-basic'][] = [
$context->msg( 'matomoanalytics-labels-pastmonth' ),
$context->msg( 'matomoanalytics-count' )->numParams( $total )->parse()
];

$pageInfo['header-basic'][] = [
$context->msg( 'matomoanalytics-labels-rawdata' ),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can get away without a system message (since it won't be displayed anyway)

$context->msg( 'matomoanalytics-count' )->rawParams( json_encode( $data ) )->parse()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$context->msg( 'matomoanalytics-count' )->rawParams( json_encode( $data ) )->parse()
htmlspecialchars( json_encode( $data ), ENT_QUOTES, 'UTF-8', true );

];
}
}
7 changes: 5 additions & 2 deletions includes/MatomoAnalyticsWiki.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ private function getData(
foreach ( $siteJson as $key => $val ) {
if ( $flat ) {
$arrayOut[$key] = $val[$jsonLabel] ?: '-';
} elseif ( $pageUrl !== null && $period == 'day' ) {
// Support Actions.getPageUrl being such a special little snowflake
$arrayOut[$key] = $val[0][$jsonLabel] ?: 0;
} else {
$arrayOut[$val[$jsonLabel]] = $val[$jsonData] ?: '-';
}
Expand Down Expand Up @@ -183,8 +186,8 @@ public function getTopPages() {
}

// Get visits for specific pages
public function getPageViews( string $pageUrl, string $period = 'range' ) {
return $this->getData( 'Actions.getPageUrl', $period, 'label', 'nb_visits', false, 30, $pageUrl );
public function getPageViews( string $pageUrl, string $periodType = 'range', int $days = 31 ) {
return $this->getData( 'Actions.getPageUrl', $periodType, 'nb_visits', 'nb_visits', false, $days, $pageUrl );
}

// Get number of visits to the site
Expand Down
89 changes: 89 additions & 0 deletions modules/ext.matomoanalytics.infochart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Add Chart.js plugin for displaying "No data to display" if no valid data
Chart.register({
id: 'noData',
afterDraw: function (chart) {
var datasets = chart.data.datasets;
var hasData = datasets.some(dataset =>
dataset.data.length > 0 &&
dataset.data.some(value => value !== null && value !== undefined && value !== 0 && !Number.isNaN(value))
);

if (!hasData) {
var ctx = chart.ctx;
var width = chart.width;
var height = chart.height;

ctx.save();
ctx.clearRect(0, 0, width, height);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '16px Arial';
ctx.fillStyle = 'gray';
ctx.fillText('No data to display', width / 2, height / 2);
ctx.restore();
}
},
});

// Function to parse JSON data from the second <td> tag and create a chart
function parseJSONAndCreateChart() {
const trElement = document.getElementById("mw-matomoanalytics-labels-rawdata");
if (!trElement) return;

// Select the second <td> element within the
const tdElements = trElement.querySelectorAll("td");
if (tdElements.length < 2) return;
const jsonData = JSON.parse(tdElements[1].textContent.trim());

const labels = Object.keys(jsonData);
const data = Object.values(jsonData).map(value => value === "-" ? null : Number(value));

// Create a popup window with Codex for the chart
const popup = new OO.ui.WindowManager();
document.body.appendChild(popup.$element[0]);
const chartWindow = new OO.ui.MessageDialog();
popup.addWindows([chartWindow]);

// Open the window and directly render the chart on success
popup.openWindow(chartWindow, {
title: 'Data Chart',
message: $('<canvas id="matomoanalytics-chart-info"></canvas>'),
size: 'large'
});

const canvas = document.getElementById("matomoanalytics-chart-info");
Comment on lines +47 to +54

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we create the canvas element and put it in a variable, and then pass that variable to the message for popup.openWindow()?

if (canvas) {
new Chart(canvas, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Data over Time',
data: data,
borderWidth: 1,
borderColor: 'blue',
backgroundColor: 'lightblue',
fill: true
}]
},
options: {
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
}
}

// Add a clickable link to trigger the chart display
document.querySelectorAll('#mw-matomoanalytics-labels-pastmonth').forEach(element => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple elements for an ID is a bit of an HTML smell...

element.style.cursor = 'pointer';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in the .less file?

element.addEventListener('click', parseJSONAndCreateChart);
});
3 changes: 3 additions & 0 deletions modules/ext.matomoanalytics.infopage.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#mw-matomoanalytics-labels-rawdata {
display: none;
}
Loading