1/* globals JSINFO, DOKU_BASE, DokuCookie */
2
3/**
4 * Modern Statistics Plugin
5 */
6class StatisticsPlugin {
7    constructor() {
8        this.data = {};
9    }
10
11    /**
12     * Initialize the statistics plugin
13     */
14    async init() {
15        try {
16            this.buildTrackingData();
17            await this.logPageView();
18            this.attachEventListeners();
19        } catch (error) {
20            console.error('Statistics plugin initialization failed:', error);
21        }
22    }
23
24    /**
25     * Build tracking data object
26     */
27    buildTrackingData() {
28        const now = Date.now();
29        const params = new URLSearchParams(window.location.search);
30        this.data = {
31            p: JSINFO.id,
32            r: document.referrer,
33            sx: screen.width,
34            sy: screen.height,
35            vx: window.innerWidth,
36            vy: window.innerHeight,
37            utm_source: params.get('utm_source') || '',
38            utm_medium: params.get('utm_medium') || '',
39            utm_campaign: params.get('utm_campaign') || '',
40            rnd: now
41        };
42    }
43
44    /**
45     * Log page view based on action
46     */
47    async logPageView() {
48        const action = JSINFO.act === 'show' ? 'v' : 's';
49        await this.logView(action);
50    }
51
52    /**
53     * Attach event listeners for tracking
54     */
55    attachEventListeners() {
56        // Track external link clicks
57        document.querySelectorAll('a.urlextern').forEach(link => {
58            link.addEventListener('click', this.logExternal.bind(this));
59        });
60
61        // Track page unload
62        window.addEventListener('beforeunload', this.logExit.bind(this));
63    }
64
65    /**
66     * Log a view or session
67     * @param {string} action 'v' = view, 's' = session
68     */
69    async logView(action) {
70        const params = new URLSearchParams(this.data);
71        const url = `${DOKU_BASE}lib/plugins/statistics/dispatch.php?do=${action}&${params}`;
72
73        try {
74            // Use fetch with keepalive for better reliability
75            await fetch(url, {
76                method: 'GET',
77                keepalive: true,
78                cache: 'no-cache'
79            });
80        } catch (error) {
81            // Fallback to image beacon for older browsers
82            const img = new Image();
83            img.src = url;
84        }
85    }
86
87    /**
88     * Log clicks to external URLs
89     * @param {Event} event Click event
90     */
91    logExternal(event) {
92        const params = new URLSearchParams(this.data);
93        const url = `${DOKU_BASE}lib/plugins/statistics/dispatch.php?do=o&ol=${encodeURIComponent(event.target.href)}&${params}`;
94
95        // Use sendBeacon for reliable tracking
96        if (navigator.sendBeacon) {
97            navigator.sendBeacon(url);
98        } else {
99            // Fallback for older browsers
100            const img = new Image();
101            img.src = url;
102        }
103
104        return true;
105    }
106
107    /**
108     * Log page exit as session info
109     */
110    logExit() {
111        const params = new URLSearchParams(this.data);
112        const url = `${DOKU_BASE}lib/plugins/statistics/dispatch.php?do=s&${params}`;
113
114        if (navigator.sendBeacon) {
115            navigator.sendBeacon(url);
116        }
117    }
118}
119
120// Initialize when DOM is ready
121if (document.readyState === 'loading') {
122    document.addEventListener('DOMContentLoaded', () => {
123        new StatisticsPlugin().init();
124    });
125} else {
126    // DOM already loaded
127    new StatisticsPlugin().init();
128}
129
130class ChartComponent extends HTMLElement {
131    connectedCallback() {
132        this.renderChart();
133    }
134
135    renderChart() {
136        const chartType = this.getAttribute('type');
137        const data = JSON.parse(this.getAttribute('data'));
138
139        console.log('data', data);
140
141        const canvas = document.createElement("canvas");
142        canvas.height = this.getAttribute('height') || 300;
143        canvas.width = this.getAttribute('width') || 300;
144
145        this.appendChild(canvas);
146
147        const ctx = canvas.getContext('2d');
148
149        // basic config
150        const config = {
151            type: chartType,
152            data: data,
153            options: {
154                responsive: false,
155            },
156        };
157
158        // percentage labels and tooltips for pie charts
159        if (chartType === "pie") {
160            // chartjs-plugin-datalabels needs to be registered
161            Chart.register(ChartDataLabels);
162
163            config.options.plugins = {
164                datalabels: {
165                    formatter: (value, context) => {
166                        const total = context.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
167                        return ((value / total) * 100).toFixed(2) + '%'; // percentage
168                    },
169                    color: '#fff',
170                }
171            };
172        }
173
174        new Chart(ctx, config);
175    }
176}
177
178customElements.define('chart-component', ChartComponent);
179