1/* global CONFIG, Fluid */ 2 3(function(window, document) { 4 'use strict'; 5 6 // Get server URL from config 7 const API_SERVER = (CONFIG.web_analytics.openkounter && CONFIG.web_analytics.openkounter.server_url) || ''; 8 9 if (!API_SERVER) { 10 console.warn('OpenKounter: server_url is not configured'); 11 return; 12 } 13 14 function getRecord(target) { 15 return fetch(`${API_SERVER}/api/counter?target=${encodeURIComponent(target)}`) 16 .then(resp => { 17 if (!resp.ok) { 18 throw new Error(`HTTP ${resp.status}: ${resp.statusText}`); 19 } 20 return resp.json(); 21 }) 22 .then(({ data, code, message }) => { 23 if (code !== 0) { 24 throw new Error(message || 'Unknown error'); 25 } 26 return { time: data.time || 0, objectId: data.target }; 27 }) 28 .catch(error => { 29 console.error('OpenKounter fetch error:', error); 30 return { time: 0, objectId: target }; 31 }); 32 } 33 34 function increment(incrArr) { 35 if (!incrArr || incrArr.length === 0) { 36 return Promise.resolve([]); 37 } 38 39 return fetch(`${API_SERVER}/api/counter`, { 40 method: 'POST', 41 headers: { 'Content-Type': 'application/json' }, 42 body: JSON.stringify({ 43 action: 'batch_inc', 44 requests: incrArr 45 }) 46 }) 47 .then(res => { 48 if (!res.ok) { 49 throw new Error(`HTTP ${res.status}: ${res.statusText}`); 50 } 51 return res.json(); 52 }) 53 .then(res => { 54 if (res.code !== 0) { 55 throw new Error(res.message || 'Failed to increment counter'); 56 } 57 return res.data; 58 }) 59 .catch(error => { 60 console.error('OpenKounter increment error:', error); 61 }); 62 } 63 64 function buildIncrement(objectId) { 65 return { target: objectId }; 66 } 67 68 // æ ¡éªæ¯å¦ä¸ºææç主æºï¼æé¤æ¬å°å¼åç¯å¢ï¼ 69 function validHost() { 70 const ignoreLocal = CONFIG.web_analytics.openkounter && CONFIG.web_analytics.openkounter.ignore_local; 71 if (ignoreLocal !== false) { 72 const hostname = window.location.hostname; 73 if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]') { 74 return false; 75 } 76 } 77 return true; 78 } 79 80 // æ ¡éªæ¯å¦ä¸ºææçç¬ç«è®¿å®¢ï¼24å°æ¶å åªè®¡ä¸æ¬¡ï¼ 81 function validUV() { 82 const key = 'OpenKounter_UV_Flag'; 83 const now = Date.now(); 84 85 try { 86 const flag = localStorage.getItem(key); 87 if (flag) { 88 const lastVisit = parseInt(flag, 10); 89 // è·ç¦»ä¸æ¬¡è®¿é®å°äº 24 å°æ¶åä¸è®¡ä¸ºæ° UV 90 if (now - lastVisit <= 86400000) { 91 return false; 92 } 93 } 94 localStorage.setItem(key, now.toString()); 95 } catch (e) { 96 // localStorage ä¸å¯ç¨æ¶é»è®¤è®¡ä¸º UV 97 console.warn('OpenKounter: localStorage is not available'); 98 } 99 return true; 100 } 101 102 function addCount() { 103 const enableIncr = CONFIG.web_analytics.enable && (!window.Fluid || !Fluid.ctx.dnt) && validHost(); 104 const getterArr = []; 105 const incrArr = []; 106 107 // 请æ±ç«ç¹ PV å¹¶èªå¢ 108 const pvCtn = document.querySelector('#openkounter-site-pv-container'); 109 if (pvCtn) { 110 const pvGetter = getRecord('site-pv').then((record) => { 111 if (enableIncr) { 112 incrArr.push(buildIncrement(record.objectId)); 113 } 114 const ele = document.querySelector('#openkounter-site-pv'); 115 if (ele) { 116 ele.innerText = (record.time || 0) + (enableIncr ? 1 : 0); 117 pvCtn.style.display = 'inline'; 118 } 119 }); 120 getterArr.push(pvGetter); 121 } 122 123 // 请æ±ç«ç¹ UV å¹¶èªå¢ 124 const uvCtn = document.querySelector('#openkounter-site-uv-container'); 125 if (uvCtn) { 126 const uvGetter = getRecord('site-uv').then((record) => { 127 const incrUV = validUV() && enableIncr; 128 if (incrUV) { 129 incrArr.push(buildIncrement(record.objectId)); 130 } 131 const ele = document.querySelector('#openkounter-site-uv'); 132 if (ele) { 133 ele.innerText = (record.time || 0) + (incrUV ? 1 : 0); 134 uvCtn.style.display = 'inline'; 135 } 136 }); 137 getterArr.push(uvGetter); 138 } 139 140 // 请æ±é¡µé¢æµè§æ°å¹¶èªå¢ 141 const viewCtn = document.querySelector('#openkounter-page-views-container'); 142 if (viewCtn) { 143 const pathConfig = CONFIG.web_analytics.openkounter.path || 'window.location.pathname'; 144 const path = eval(pathConfig); 145 const target = decodeURI(path.replace(/\/*(index.html)?$/, '/')); 146 147 const viewGetter = getRecord(target).then((record) => { 148 if (enableIncr) { 149 incrArr.push(buildIncrement(record.objectId)); 150 } 151 const ele = document.querySelector('#openkounter-page-views'); 152 if (ele) { 153 ele.innerText = (record.time || 0) + (enableIncr ? 1 : 0); 154 viewCtn.style.display = 'inline'; 155 } 156 }); 157 getterArr.push(viewGetter); 158 } 159 160 // æ¹éåèµ·ç»è®¡è¯·æ± 161 Promise.all(getterArr).then(() => { 162 if (enableIncr && incrArr.length > 0) { 163 increment(incrArr); 164 } 165 }).catch(error => { 166 console.error('OpenKounter error:', error); 167 }); 168 } 169 170 addCount(); 171 172})(window, document); 173
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.