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