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