WoTStatScript - Forums

Adds stats and links for posts on official World of Tanks forums

当前为 2017-03-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WoTStatScript - Forums
  3. // @version 0.9.17.1.0
  4. // @description Adds stats and links for posts on official World of Tanks forums
  5. // @author Orrie
  6. // @contributor seriych
  7. // @namespace http://forum.worldoftanks.eu/index.php?/topic/263423-
  8. // @icon https://i.imgur.com/AxOhQ7C.png
  9. // @include /^http:\/\/forum\.worldoftanks\.(eu|com|ru|asia|kr)\/\S+(\/topic\/|\?showtopic=)/
  10. // @include /^http:\/\/forum\.worldoftanks\.(eu|com|ru|asia|kr)\/index\.php\?app=members&module=messaging&section=view&do=showConversation&topicID=\d+/
  11. // @include /^http:\/\/forum\.worldoftanks\.(eu|com|ru|asia|kr)\/index\.php\?\/forum/\S+/
  12. // @grant GM_xmlhttpRequest
  13. // @connect api.worldoftanks.eu
  14. // @connect api.worldoftanks.ru
  15. // @connect api.worldoftanks.com
  16. // @connect api.worldoftanks.asia
  17. // @connect api.worldoftanks.kr
  18. // @connect www.wnefficiency.net
  19. // @connect puu.sh
  20. // @license MIT License
  21. // ==/UserScript==
  22. (function() {
  23. // global vars
  24. var d = document;
  25.  
  26. // get server info and webpage
  27. var wg = {host:d.location.host, href:d.location.href, clan:{}};
  28. wg.srv = wg.host.match(/\.(eu|ru|com|asia|kr)/)[1].replace(/com/,"na");
  29. wg.topic = /(\/topic\/|\?showtopic=|messaging\&)/.test(wg.href);
  30. wg.forum = /\/forum\//.test(wg.href);
  31. wg.login = !!d.getElementsByClassName('js-cm-login-link')[0];
  32.  
  33. // server, API and cluster settings
  34. var sc = {
  35. vers: ((GM_info) ? GM_info.script.version : ""),
  36. host: "http://greasyfork.org/scripts/660-wotstatscript-forumsextendedstat",
  37. user: {
  38. wl: "http://forum.wotlabs.net/index.php?/user/1618-orrie/",
  39. wot: "http://worldoftanks.eu/community/accounts/505838943-Orrie/"
  40. },
  41. top: {
  42. eu: "http://forum.worldoftanks.eu/index.php?showtopic=263423",
  43. na: "http://forum.worldoftanks.com/index.php?showtopic=404652"
  44. },
  45. cred: { // translators
  46. cs: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/500744969/'>Crabtr33</a></td><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/508323506/'>Ragnarocek</a></td></tr><tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/508904714/'>jViks</a></td></tr>" ,
  47. de: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/504873051/'>ArtiOpa</a></td><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/501118529/'>Crakker</a></td></tr><tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/501072645/'>multimill</a></td><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/500373105/'>coolathlon</a></td></tr>",
  48. fr: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/506641783/'>SuperPommeDeTerre</a></td></tr>",
  49. pl: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/501801562/'>KeluMocy</a></td><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/504412736/'>pokapokami</a></td></tr>",
  50. es: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/512759883/'>Frodo45127</a></td></tr>",
  51. tr: "<tr><td><a class='b-orange-arrow' href='http://worldoftanks.eu/community/accounts/500400806/'>Ufuko</a></td></tr>",
  52. ru: "<tr><td>dimon222</td></tr>"
  53. },
  54. srv: {
  55. s: "en",
  56. wl: false, // wotlabs
  57. nm: false, // noobmeter
  58. vb: false, // vbaddict
  59. ws: false, // wotstats
  60. wr: false, // wotreplays
  61. ct: false, // clan-tools
  62. wlf: false // wot-life
  63. },
  64. api: {
  65. wg_key: "a7595640a90bf2d19065f3f2683b171c"
  66. },
  67. sym: ",",
  68. wn: "https://puu.sh/uLoOx/ac9982e39c.json",
  69. date: Date.now(),
  70. dateFormat: {ru: "ru-RU", eu: "en-GB", na: "en-US", asia: "en-AU", kr: "ko-KR"},
  71. web: {
  72. gecko: typeof InstallTrigger !== 'undefined',
  73. opera: !!window.opera || /opera|opr/i.test(navigator.userAgent),
  74. chrome: !!window.chrome && !!window.chrome.webstore,
  75. safari: /constructor/i.test(window.HTMLElement)
  76. }
  77. };
  78.  
  79. // script functions
  80. var sf = {
  81. apiInfoHnd: function (resp) { // processing information from player API
  82. var data = JSON.parse(resp).data;
  83. for (var a in data) {
  84. if (data.hasOwnProperty(a)) {
  85. var pData = data[a];
  86. if (pData !== null) {
  87. // store stats
  88. var pDataStats = pData.statistics.all;
  89. s[pData.account_id].u = {
  90. name: pData.nickname,
  91. id: pData.account_id,
  92. cid: pData.clan_id,
  93. bat: pDataStats.battles,
  94. win: (pDataStats.wins/pDataStats.battles)*100,
  95. dmg: pDataStats.damage_dealt/pDataStats.battles,
  96. frag: pDataStats.frags/pDataStats.battles,
  97. spot: pDataStats.spotted/pDataStats.battles,
  98. def: pDataStats.dropped_capture_points/pDataStats.battles,
  99. wgr: pData.global_rating,
  100. lng: pData.client_language,
  101. time: pData.created_at,
  102. ban: pData.ban_time
  103. };
  104. }
  105. else {
  106. // store stats
  107. s[parseFloat(a)].u = {
  108. bat: 0
  109. };
  110. }
  111. }
  112. }
  113. sf.request(sc.api.v, sf.apiVehHnd);
  114. },
  115. apiVehHnd: function (resp) { // processing information from vehicle API and calculate WN8
  116. var data = JSON.parse(resp).data;
  117. for (var p in data) {
  118. if (data.hasOwnProperty(p)) {
  119. var vData = data[p];
  120. if (vData !== null) {
  121. var rWin, rDmg, rFrag, rSpot, rDef, wn8 = 0, battles = 0;
  122. if (s[p].u.bat > 0) {
  123. for (var v in vData) {
  124. if (vData.hasOwnProperty(v)) {
  125. for (var _so=0, _so_len = statArr.length; _so<_so_len; _so++) {
  126. if (statArr[_so].IDNum == vData[v].tank_id) {
  127. var vehStat = statArr[_so],
  128. dataBattles = vData[v].statistics.battles;
  129. s[p].v.frag += vehStat.expFrag * dataBattles;
  130. s[p].v.dmg += vehStat.expDamage * dataBattles;
  131. s[p].v.spot += vehStat.expSpot * dataBattles;
  132. s[p].v.def += vehStat.expDef * dataBattles;
  133. s[p].v.win += vehStat.expWinRate * dataBattles;
  134. battles += dataBattles;
  135. break;
  136. }
  137. }
  138. }
  139. }
  140. rWin = Math.max(((s[p].u.win/(s[p].v.win/battles)-0.71)/(1-0.71)),0);
  141. rDmg = Math.max(((s[p].u.dmg/(s[p].v.dmg/battles)-0.22)/(1-0.22)),0);
  142. rFrag = Math.max(Math.min(rDmg+0.2,((s[p].u.frag/(s[p].v.frag/battles)-0.12)/(1-0.12))),0);
  143. rSpot = Math.max(Math.min(rDmg+0.1,((s[p].u.spot/(s[p].v.spot/battles)-0.38)/(1-0.38))),0);
  144. rDef = Math.max(Math.min(rDmg+0.1,((s[p].u.def /(s[p].v.def /battles)-0.10)/(1-0.10))),0);
  145. wn8 = 980*rDmg + 210*rDmg*rFrag + 155*rFrag*rSpot + 75*rDef*rFrag + 145*Math.min(1.8,rWin);
  146. }
  147. // store wn8
  148. s[p].wn8 = sf.color(wn8,"wn8",0);
  149. }
  150. }
  151. }
  152. sf.statInsert();
  153. },
  154. statInsert: function () { // insert stats and links to every post
  155. for (var y in s) {
  156. if (s.hasOwnProperty(y)) {
  157. var iPost = postObj.ids.indexOf(y), flag;
  158. if (iPost >- 1 && s[y].u.id) {
  159. if (wg.topic) {
  160. var userStats = [
  161. "<td>"+loc[1]+"</td><td>"+sf.color((s[y].u.bat > 0) ? s[y].u.win : 0,"wr",2,"%")+"</td>",
  162. "<td>"+loc[2]+"</td><td>"+sf.color(s[y].u.bat,"bat",0,"")+"</td>",
  163. "<td>"+loc[3]+"</td><td>"+sf.color(s[y].u.wgr,"pr",0,"")+"</td>",
  164. "<td>"+loc[4]+"</td><td>"+s[y].wn8+"</td>"
  165. ],
  166. userLinks = [
  167. [
  168. ["<a target='_blank' href='http://worldoftanks."+((wg.srv == "na") ? "com" : wg.srv)+"/community/accounts/"+s[y].u.id+"-"+s[y].u.name+"/'>Player Profile</a>"],
  169. [sc.srv.wl, "<a target='_blank' href='http://wotlabs.net/"+sc.srv.wl+"/player/"+s[y].u.name+"'>WoTLabs</a>"]
  170. ],
  171. [
  172. [sc.srv.vb, "<a target='_blank' href='http://www.vbaddict.net/player/"+s[y].u.name.toLowerCase()+"-"+sc.srv.vb+"'>vBAddict</a>"],
  173. [sc.srv.nm, "<a target='_blank' href='http://noobmeter.com/player/"+sc.srv.nm+"/"+s[y].u.name+"'>Noobmeter</a>"]
  174. ],
  175. [
  176. [sc.srv.ws, "<a target='_blank' href='http://wotstats.org/stats/"+sc.srv.ws+"/"+s[y].u.name+"/'>WoTstats</a>"],
  177. [sc.srv.ct, "<a target='_blank' href='http://clantools.us/servers/"+sc.srv.ct+"/players?id="+s[y].u.id+"'>Clan Tools</a>"]
  178. ],
  179. [
  180. [sc.srv.wr, "<a target='_blank' href='http://wotreplays."+sc.srv.wr+"/player/"+s[y].u.name+"'>WoTReplays</a>"],
  181. (wg.srv=="ru") ? [sc.srv.wr, "<a target='_blank' href='http://wots.com.ua/user/stats/"+s[y].u.name+"'>WoTS.com.ua</a>"] : [sc.srv.wlf, "<a target='_blank' href='http://en.wot-life.com/"+sc.srv.wlf+"/player/"+s[y].u.name+"/'>WoT-Life</a>"]
  182. ]
  183. ];
  184. for (var _i=0, _i_len = postObj.num[iPost].length; _i<_i_len; _i++) {
  185. var post = postObj.post[postObj.num[iPost][_i]],
  186. groupTitle = post.getElementsByClassName("group_title")[0],
  187. basicInfo = post.getElementsByClassName("basic_info")[0],
  188. infoClass = post.getElementsByClassName("author_info")[0],
  189. statTable = sf.elem("table", "t-table-stats", ""),
  190. urlTable = sf.elem("div", "b-table-links", "<table class='t-table-links'><tbody></tbody></table>");
  191. // insert stats
  192. for (var _sr=0, _sr_len = userStats.length; _sr<_sr_len; ++_sr) {
  193. statTable.appendChild(sf.elem("tr", "", userStats[_sr]));
  194. }
  195. // insert links
  196. for (var _l=0, _l_len = userLinks.length; _l<_l_len; ++_l) {
  197. var uRow = sf.elem("tr", "", "");
  198. for (var _lr=0, _lr_len = userLinks[_l].length; _lr<_lr_len; ++_lr) {
  199. uRow.appendChild((userLinks[_l][_lr][0] && userLinks[_l][_lr][1]) ? sf.elem("td", "", userLinks[_l][_lr][1]) : sf.elem("td", "", userLinks[_l][_lr][0]));
  200. }
  201. urlTable.firstElementChild.firstElementChild.appendChild(uRow);
  202. }
  203. // modify date
  204. basicInfo.lastElementChild.lastElementChild.innerHTML = new Date(s[y].u.time*1000).toLocaleDateString(sc.dateFormat[wg.srv]);
  205. // add client flag, if not on Russian forum
  206. if (wg.srv !== "ru") {
  207. flag = sf.elem("img", "i-xvm-lang", "", "", "https://bytebucket.org/seriych/worldoftanksforumextendedstat.user.js/raw/tip/data/img/lang/"+s[y].u.lng+".png");
  208. flag.title = s[y].u.lng.toUpperCase()+" "+loc[0];
  209. flag.addEventListener('error', sf.flag);
  210. groupTitle.appendChild(flag);
  211. }
  212. // add bantime if it exists
  213. if (s[y].u.ban) {
  214. var memTitle = post.getElementsByClassName("member_title")[0];
  215. memTitle.textContent = "Banned: "+ new Date(s[y].u.ban*1000).toLocaleString(sc.dateFormat[wg.srv]);
  216. memTitle.classList.add("member_banned");
  217. }
  218. basicInfo.insertBefore(statTable, basicInfo.lastElementChild);
  219. infoClass.appendChild(urlTable);
  220. }
  221. }
  222. else if (wg.forum) {
  223. for (var _r=0, _r_len = postObj.num[iPost].length; _r<_r_len; _r++) {
  224. var statCell, id_url = postObj.span[postObj.num[iPost][_r]].getElementsByClassName("url")[0],
  225. threadRow = postObj.span[postObj.num[iPost][_r]].parentNode.parentNode,
  226. threadRowClsList = threadRow.classList;
  227. if (threadRowClsList.contains("announcement")) {
  228. statCell = threadRow.insertCell(1);
  229. }
  230. else if (threadRowClsList.contains("__topic")) {
  231. statCell = threadRow.insertCell(3);
  232. }
  233. statCell.className = "col_f_stats";
  234. if (!id_url || s[y].u.bat === 0) {
  235. statCell.appendChild(sf.elem("span", "s-no-stats", loc[6]));
  236. }
  237. else {
  238. var statsRow = [
  239. "<td>"+loc[1]+"</td><td>"+sf.color((s[y].u.bat > 0) ? s[y].u.win : 0,"wr",2,"%")+"</td><td>"+loc[2]+"</td><td>"+sf.color(s[y].u.bat,"bat",0,"")+"</td>",
  240. "<td>"+loc[3]+"</td><td>"+sf.color(s[y].u.wgr,"pr",0,"")+"</td><td>"+loc[4]+"</td><td>"+s[y].wn8+"</td>",
  241. ],
  242. rowTable = sf.elem("table", "t-row-stats", "");
  243. for (var _rr=0, _rr_len = statsRow.length; _rr<_rr_len; ++_rr) {
  244. rowTable.appendChild(sf.elem("tr", "", statsRow[_rr]));
  245. }
  246. if (wg.srv !== "ru") {
  247. flag = sf.elem("img", "i-xvm-lang", "", "", "https://bytebucket.org/seriych/worldoftanksforumextendedstat.user.js/raw/tip/data/img/lang/"+s[y].u.lng+".png");
  248. flag.title = s[y].u.lng.toUpperCase()+" "+loc[0];
  249. flag.addEventListener('error', sf.flag);
  250. statCell.appendChild(flag);
  251. }
  252. statCell.appendChild(rowTable);
  253. }
  254. }
  255. }
  256. }
  257. }
  258. }
  259. },
  260. color: function (input, type, dec, sym) { // color formatting
  261. var color = colArr.dft[0],
  262. output = input.toFixed(dec);
  263. if (sym) {
  264. output += sym;
  265. }
  266. if (input >= 1000) {
  267. output = input.toFixed(dec).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1"+sc.sym);
  268. }
  269. for (var c in colArr) {
  270. if (colArr.hasOwnProperty(c)) {
  271. if (input >= colArr[c][colArr.id[type]]) {
  272. color = colArr[c][0]; break;
  273. }
  274. }
  275. }
  276. return "<font color='"+color+"'>"+output+"</font>";
  277. },
  278. elem: function (tag, name, html, type, src) { // element creation
  279. var element = d.createElement(tag);
  280. if (name) {element.className = name;}
  281. if (html) {
  282. if (/</.test(html)) {
  283. element.innerHTML = html;
  284. }
  285. else {
  286. element.textContent = html;
  287. }
  288. }
  289. if (type) {element.type = type;}
  290. if (src) {element.src = src;}
  291. return element;
  292. },
  293. flag: function (elem) { // image error picture
  294. elem.src=uri.q_mark;
  295. },
  296. settings: function (name, text) { // script menu handler
  297. var setItem = sf.elem("li", "b-settingItem"),
  298. setDiv = sf.elem("div", "b-settingParent b-"+name, "<a>"+text+"</a>");
  299. switch(name) {
  300. case ("wnRefresh"):
  301. setDiv.addEventListener('click', function() {localStorage.removeItem("wnExpValues"); location.reload();}, false);
  302. break;
  303. default: break;
  304. }
  305. setItem.appendChild(setDiv);
  306. return setItem;
  307. },
  308. links: function (parent, links, type) { // statistic links handler
  309. var linksFragment = d.createDocumentFragment();
  310. for (var _l=0, _l_len = links.length; _l<_l_len; ++_l) {
  311. switch(type) {
  312. case ("table"):
  313. var link = sf.elem("tr");
  314. for (var _lr=0, _lr_len = links[_l].length; _lr<_lr_len; ++_lr) {
  315. link.appendChild((links[_l][_lr][0] && links[_l][_lr][1]) ? sf.elem("td", "", links[_l][_lr][1]) : sf.elem("td", "", links[_l][_lr][0]));
  316. }
  317. linksFragment.appendChild(link);
  318. break;
  319. case ("list"):
  320. if (links[_l] instanceof HTMLElement) {
  321. linksFragment.appendChild(links[_l]);
  322. }
  323. else {
  324. linksFragment.appendChild((links[_l][0] && links[_l][1]) ? sf.elem("li", "", links[_l][1]) : sf.elem("li", "statname", links[_l][0]));
  325. }
  326. break;
  327. default: break;
  328. }
  329. }
  330. parent.appendChild(linksFragment);
  331. },
  332. storage: function (name, data, type, mode) { // localstorage handler
  333. var storage;
  334. switch(type) {
  335. case ("set"):
  336. if (mode == "string") {
  337. data = JSON.stringify(data);
  338. }
  339. storage = localStorage.setItem(name, data);
  340. break;
  341. case ("get"):
  342. storage = localStorage.getItem(name);
  343. if (mode == "parse") {
  344. storage = JSON.parse(storage);
  345. }
  346. break;
  347. default: break;
  348. }
  349. return storage;
  350. },
  351. wn: function (resp) { // wnefficiency handler
  352. sf.storage("wnExpValues", resp, "set");
  353. sf.storage("wnExpDate", sc.date, "set");
  354. sf.storage("wnExpVers", [sc.vers, JSON.parse(resp).header.version], "set", "string");
  355. location.reload();
  356. },
  357. request: function (url, handler) { // request handler
  358. GM_xmlhttpRequest({
  359. method: "GET",
  360. url: url,
  361. headers: {
  362. "Accept": "application/json"
  363. },
  364. onload: function(resp) {
  365. if (resp.status == 200) {
  366. handler(resp.responseText);
  367. }
  368. else {
  369. console.error("Error accessing", url, resp.readyState, resp.status, resp.statusText);
  370. }
  371. },
  372. onerror: function(resp) {
  373. console.error("Error accessing", url, resp.readyState, resp.status, resp.statusText);
  374. }
  375. });
  376. }
  377. };
  378.  
  379. // region settings for external sites
  380. switch(wg.srv) {
  381. case ("eu"): // eu server
  382. sc.srv.wl = sc.srv.nm = sc.srv.vb = sc.srv.ws = sc.srv.wr = sc.srv.ct = sc.srv.wlf = wg.srv;
  383. break;
  384. case ("ru"): // ru server
  385. sc.srv.wl = sc.srv.nm = sc.srv.vb = sc.srv.ws = sc.srv.wr = sc.srv.ct = sc.srv.wlf = wg.srv;
  386. sc.srv.s = "ru";
  387. sc.sym = " ";
  388. break;
  389. case ("com"): // na server
  390. sc.srv.wl = sc.srv.nm = sc.srv.vb = sc.srv.ws = sc.srv.ct = "na"; sc.srv.wr = "com";
  391. break;
  392. case ("asia"): // asia server
  393. sc.srv.wl = sc.srv.nm = sc.srv.vb = sc.srv.ws = "sea"; sc.srv.ct = wg.srv; sc.srv.wr = "com";
  394. break;
  395. case ("kr"): // korean server
  396. sc.srv.wl = sc.srv.nm = sc.srv.vb = sc.srv.ws = sc.srv.ct = sc.srv.ch = wg.srv; sc.srv.wr = "com";
  397. break;
  398. default: break;
  399. }
  400.  
  401. // data uri
  402. var uri = {
  403. icon_arrow:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPwAAAAJCAMAAAAhKrH/AAAAV1BMVEUAAAD///+TKCf9AQmTLiX9AQmTMir9AQmTLif9AQmTMSz9AQmTMir9AQmTMyn9AQmTMirvGgKTMirsIAGTMirwGQOTMiqTMirsIAGaNDGgNzfqJwDrJABtE0DNAAAAGnRSTlMAABERIiIzM0REVVVmZnd3iIqZmrvDzN3g7thzQuwAAACHSURBVHja5dVLDsIwDEXRCySlP0IMoXXs7H+dDBASA1bQ3B0cPclm2Fe2wrfTQeO3qwqqAKWek80HxfO/l1/EBRgtU2tf+KkJ7TO9hdVSV3jU42f6ZClY6Qt/d4n+BGol29jTwQN1pE2QbA610BVefImuwL7xsNAXXhVpEYY8kNfO/rwsyA3ekEsOT2YDLE8AAAAASUVORK5CYII=",
  404. q_mark: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAANCAYAAACgu+4kAAAAh0lEQVQoz2OwsbGxtre3jwTiBBJxJEgvA4jBQCYA6wWZhkVOFIjLgPgOEH8A4llArIDFgARcBsgCsRkQywGxLhC3AXEtKQYgA5DN6UCcRo4BEkCcDcSVQMxLqgHcQJwPxNVAzIMjEPEaIAXEJUCcgScWiAoDBnINEAbieiCuobkBlKVESvMCADnAReqxtj3zAAAAAElFTkSuQmCC"
  405. };
  406.  
  407. // fetch wnefficiency values - check if array exists in localStorage, otherwise fetch and reload page
  408. var wn = {
  409. values: sf.storage("wnExpValues", "", "get", "parse"),
  410. date: sf.storage("wnExpDate", "", "get", "parse")+12096e5 >= sc.date, // true if timestamp is less than 2 weeks old, refresh list if false.
  411. vers: sf.storage("wnExpVers", "", "get", "parse") || ""
  412. }, statArr = [];
  413. if (wn.vers[0]==sc.vers && wn.values && wn.date) {
  414. statArr = wn.values.data;
  415. }
  416. else {
  417. sf.request(sc.wn, sf.wn);
  418. }
  419.  
  420. // style contents
  421. var style = sf.elem("style", "wotstatscript", "", "text/css"),
  422. styleText = [
  423. // settings menu rules
  424. "#common_menu .menu-settings {color: #7C7E80; display: inline-block;}",
  425. "#common_menu .menu-settings .cm-user-menu-link {margin: 0 10px 0 0;}",
  426. "#common_menu .menu-settings .cm-user-menu-link_cutted-text {max-width: unset;}",
  427. "#common_menu .menu-settings .cm-user-menu {min-width: 200px; padding: 15px;}",
  428. "#common_menu .menu-settings .cm-parent-link:hover {cursor: pointer;}",
  429. "#common_menu .menu-settings .b-settingItem {margin: 6px 0px; text-align: center;}",
  430. "#common_menu .menu-settings label {display: table; line-height: normal; cursor: pointer; margin: 0 auto;}",
  431. "#common_menu .menu-settings .l-box {display: none;}",
  432. "#common_menu .menu-settings .b-checkbox {height: 16px; width: 16px; float: left; margin-right: 5px;}",
  433. "#common_menu .menu-settings .b-checkbox span {height: 16px; width: 16px;}",
  434. "#common_menu .menu-settings .b-combobox-label__checked {color: #DCDCDC;}",
  435. "#common_menu .menu-settings .b-settingItem .b-combobox-label:hover {color: #DCDCDC;}",
  436. "#common_menu .menu-settings .b-settingItem .b-combobox-label:hover .b-checkbox {background-position: 0px -34px; box-shadow: 0px 0px 10px 1px rgba(191, 166, 35, 0.15), 0px 0px 3px 1px rgba(191, 166, 35, 0.25);}",
  437. "#common_menu .menu-settings .b-settingItem .b-combobox-label:hover .b-checkbox.b-checkbox__checked {background-position: 0px -68px;}",
  438. "#common_menu .menu-settings textarea.l-textarea {background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 2px; color: #FFFFFF; line-height: normal; padding: 5px; min-height: 50px; margin: 5px 0 5px 0; min-width: 175px;}",
  439. "#common_menu .menu-settings textarea::-webkit-input-placeholder {color: #FFFFFF;}",
  440. "#common_menu .menu-settings textarea::-moz-placeholder {color: #FFFFFF;}",
  441. "#common_menu .menu-settings .b-settingParent {line-height: 26px;}",
  442. "#common_menu .menu-settings .b-settingParent a {cursor: pointer; color: #B1B2B3; text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.5);}",
  443. "#common_menu .menu-settings .b-settingParent a:hover {color: #FFFFFF; text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75); text-decoration: underline;}",
  444. "#common_menu .menu-settings .settingCredits {margin: 2px 0px;}",
  445. "#common_menu .menu-settings .settingCredits h1 {color: #B1B2B3;}",
  446. "#common_menu .menu-settings .settingCredits table {font-size: 12px; margin: 0 auto; width: unset;}",
  447. "#common_menu .menu-settings .settingCredits table td {padding: 0 5px;}",
  448. "#common_menu .menu-settings .settingCredits p {font-size: 12px; padding: 2px 0;}",
  449. "#common_menu .menu-settings .settingCredits .b-orange-arrow {color: #F25322; line-height: 14px; padding-right: 9px;}",
  450. "#common_menu .menu-settings .settingCredits .b-orange-arrow:hover {color: #FF7432;}",
  451. "#common_menu .menu-settings .settingCredits.settingSeperator {border-top: 1px dashed #212123; margin-top: 6px; padding-top: 12px;}",
  452. "#common_menu .menu-settings .settingCredits.settingLinks a {margin: 0 5px;}",
  453. // forum rules
  454. ".topic_list {table-layout: auto}",
  455. ".col_f_stats {width: 200px;}",
  456. ".col_f_preview {width: 10px !important;}",
  457. ".col_f_views {width: auto;}",
  458. ".col_f_post {width: auto;}",
  459. ".col_f_stats .i-xvm-lang {margin: 6px 0 0 0;}",
  460. ".t-row-stats {float: right; table-layout: fixed; width: 175px;}",
  461. ".realm_ru .t-row-stats {width: 200px;}",
  462. "table.ipb_table .t-row-stats td {border-bottom: 0; font-size: 11px; padding: 0;}",
  463. "#announcements .t-row-stats td {border-bottom: 0;}",
  464. ".s-no-stats {color: #A03737; display: table; font-size: 14px; margin: 0 auto;}",
  465. // thread rules
  466. ".author_info {min-height: 310px; padding: 0 10px 10px 14px;}",
  467. ".user_details > br {display: none;}",
  468. ".author_info .member_title.member_banned {color: #CD3333;}",
  469. ".basic_info {margin: 0 0 4px;}",
  470. ".post_count.margin-bottom {margin: 0 0 5px;}",
  471. ".battles_count {display: none;}",
  472. ".i-xvm-lang {vertical-align: text-top;}",
  473. ".t-table-stats {margin: 5px 0; width: auto;}",
  474. ".t-table-stats td {padding: 0 5px 0 0; line-height: 16px;}",
  475. ".t-table-stats td:last-of-type {font-weight: bold;}",
  476. ".b-table-links {height: 25px; margin: 5px 0px 0px;}",
  477. ".t-table-links {background: #EDEDED; border: 1px solid #d5d5d5; border-radius: 3px; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1), 0 0 3px 3px rgba(255, 255, 255, 0.2); display: inline-block; overflow: hidden; padding: 3px 3px 0; position: absolute; text-overflow: ellipsis; white-space: nowrap; height: "+((sc.web.chrome) ? "20px" : "25px")+"; width: 90px; z-index: 1;}",
  478. ".t-table-links:hover {border-color: #7D7D7D; height: auto; width: auto;}",
  479. ".t-table-links tbody {display: table; width: 180px;}",
  480. ".t-table-links td {padding: 0 0 2px; font-weight: bold;}",
  481. ".t-table-links td a { background: url("+uri.icon_arrow+") no-repeat scroll 0 2px rgba(0, 0, 0, 0); padding: 0 0 0 10px; vertical-align: middle;}",
  482. ".t-table-links td a:hover {background: url("+uri.icon_arrow+") no-repeat scroll -244px 2px rgba(0, 0, 0, 0);}",
  483. ".t-table-links tr:last-of-type td {}",
  484. // korean realm widths
  485. ".realm_kr .t-table-links {width: 108px;}",
  486. ".realm_kr .t-table-links:hover {width: 215px;}",
  487. ".realm_kr .t-table-links tbody {width: 215px;}"
  488. ];
  489. style.textContent = styleText.join("");
  490. d.head.appendChild(style);
  491. // end style
  492.  
  493. // colour scale array
  494. var colArr = {
  495. // col wr bat wn8 wn7 eff nm pr
  496. sUni: [ "#5A3175", 65, 30000, 2900, 2050, 2050, 2000 ], // 99.99% super unicum
  497. uni: [ "#83579D", 60, 25000, 2450, 1850, 1800, 1950, 9930 ], // 99.90% unicum
  498. gr8: [ "#3972C6", 56, 21000, 2000, 1550, 1500, 1750, 8525 ], // 99.00% great
  499. vGud: [ "#4099BF", 54, 17000, 1600, 1350 ], // 95.00% very good
  500. good: [ "#4D7326", 52, 13000, 1200, 1100, 1200, 1450, 6340 ], // 82.00% good
  501. aAvg: [ "#849B24", 50, 10000, 900 ], // 63.00% above average
  502. avg: [ "#CCB800", 48, 7000, 650, 900, 900, 1250, 4185 ], // 40.00% average
  503. bAvg: [ "#CC7A00", 47, 3000, 450, 700, 600, 1150, 2020 ], // 20.00% below average
  504. bas: [ "#CD3333", 46, 1000, 300, 500 ], // 6.00% basic
  505. beg: [ "#930D0D", 0, 0, 0, 0, 0, 0, 0 ], // 0.00% beginner
  506. dft: [ "#6B6B6B" ], // default
  507. id: { "col": 0, "wr": 1, "bat": 2, "wn8": 3, "wn7": 4, "eff": 5, "nm": 6, "pr": 7 } // type identifier
  508. };
  509.  
  510. // localization
  511. var loc = [
  512. { en: "Client", ru: "Клиент", cs: "Klient", fr: "Client"},
  513. { en: "Winrate:", ru: "Винрейт:", cs: "Winrate", fr: "Ratio V."},
  514. { en: "Battles:", ru: "Боев:", cs: "Bitev", fr: "Batailles"},
  515. { en: "Rating:", ru: "Рейтинг:", cs: "Hodnocení", fr: "Côte"},
  516. { en: "WN8:", ru: "WN8:", cs: "WN8:", fr: "WN8"},
  517. { en: "Please Login for Stats", ru: "Please Login for Stats", cs: "Přihlaš se pro statistiky", fr: "Veuillez vous connecter pôr les statistiques"},
  518. { en: "No Stats Found", ru: "No Stats Found", cs: "Stat. nenalezeny", fr: "Aucune statistique trouvée"},
  519. { en: "Script Menu", ru: "Script Menu", cs: "Menu skritpu", fr: "Menu du script"},
  520. { en: "Refresh WN8 Table", ru: "Refresh WN8 Table", cs: "Obnov WN8", fr: "Rafraîchir la table WN8"},
  521. { en: "Script Author:", ru: "Script Author:", cs: "Autor skriptu:", de: "Script-Autor:", fr: "Auteur du script :", pl: "Script Author:", es:"Script Author:", tr: "Script Author:"},
  522. { en: "Contributors (EN):", ru: "Contributors (RU):", cs: "Kontributoři (CZ):", de: "Contributors (DE):", fr: "Contributeurs (FR):", pl: "Contributors (PL):", es:"Contributors (ES):", tr: "Contributors (TR):"}
  523. //{ en: "f00_en", ru: "f00_ru", fr: "f00_fr"},
  524. ];
  525. // process localization
  526. for (var _l=0, l_len = loc.length; _l<l_len; _l++) {
  527. loc[_l] = loc[_l][sc.srv.s];
  528. }
  529.  
  530. // script link
  531. var userSet_div = sf.elem("div", "menu-settings menu-top_item", "<a class='cm-user-menu-link' href='#' onClick='return false;'><span class='cm-user-menu-link_cutted-text'>"+loc[7]+"</span><span class='cm-arrow'></span></span>"),
  532. userSet_list = sf.elem("ul", "cm-user-menu"),
  533. userSet_list_items = [
  534. sf.settings("wnRefresh", loc[8]+" [v"+wn.vers[1]+"]"),
  535. sf.elem("li", "b-settingItem settingCredits settingSeperator", "<p>Version: "+sc.vers+"</p>"),
  536. sf.elem("li", "b-settingItem settingCredits", "<p>"+loc[9]+" <a class='b-orange-arrow' href='"+sc.user.wot+"'>Orrie</a></p>"+((sc.cred[sc.loc]) ? "<p>"+loc[10]+"</p><table>"+sc.cred[sc.loc]+"</table>" : "")),
  537. sf.elem("li", "b-settingItem settingCredits settingLinks", "<p><a class='b-orange-arrow' href='"+sc.host+"'>Greasy Fork</a><a class='b-orange-arrow' href='"+((wg.srv == "na") ? sc.top.na : sc.top.eu)+"'>Support Thread</a></p>")
  538. ],
  539. navMenu = d.getElementById('common_menu'),
  540. navUser = navMenu.getElementsByClassName('cm-menu__user')[0];
  541. sf.links(userSet_list, userSet_list_items, "list");
  542. userSet_div.firstElementChild.addEventListener('click', function() {this.classList.toggle('cm-user-menu-link__opened'); this.nextSibling.classList.toggle('cm-user-menu__opened');}, false);
  543. userSet_div.appendChild(userSet_list);
  544. if (navUser) {
  545. navUser.appendChild(userSet_div);
  546. }
  547. else {
  548. var navLook = new MutationObserver(function() {
  549. var navUser = navMenu.getElementsByClassName('cm-menu__user')[0];
  550. navUser.appendChild(userSet_div);
  551. navLook.disconnect();
  552. });
  553. navLook.observe(navMenu, {childList: true});
  554. }
  555.  
  556. // formula calculations and variables
  557. // create global post variable
  558. var postObj = {
  559. post: d.querySelectorAll(".post_wrap, .post_wrap__wg"),
  560. span: d.querySelectorAll("span.desc.lighter.blend_links"),
  561. cls: [],
  562. ids: [],
  563. num: []
  564. },
  565. s = {};
  566. switch(true) {
  567. case (wg.topic):
  568. postObj.cls = postObj.post; break;
  569. case (wg.forum):
  570. postObj.cls = postObj.span; break;
  571. default: break;
  572. }
  573.  
  574. // fetch userids and store all posts into one obj for later use
  575. if (wg.topic || (wg.forum && wg.login === false)) {
  576. for (var _t=0, _t_len = postObj.cls.length; _t<_t_len; _t++) {
  577. var id;
  578. switch(true) {
  579. case (wg.topic):
  580. id = postObj.post[_t].getElementsByClassName("ipsUserPhotoLink")[0].getAttribute('href').match(/\-(\d+)\//)[1]; break;
  581. case (wg.forum):
  582. var id_url = postObj.span[_t].getElementsByClassName("url")[0];
  583. if (id_url) {
  584. id = id_url.getAttribute('href').match(/\-(\d+)\//)[1];
  585. }
  586. break;
  587. default: break;
  588. }
  589. if (!isNaN(id)) {
  590. var users = postObj.ids.length,
  591. index = postObj.ids.indexOf(id);
  592. s[id] = {u:{},v:{frag:0,dmg:0,spot:0,def:0,win:0},wn8:""};
  593. if (index>-1) {
  594. postObj.num[index][postObj.num[index].length] = _t;
  595. }
  596. else {
  597. postObj.ids[users] = id;
  598. postObj.num[users] = [_t];
  599. }
  600. }
  601. }
  602. }
  603. else {
  604. navUser.insertBefore(sf.elem("div", "cm-parent-link b-login-msg", "<div>"+loc[5]+"</div>"), navUser.firstChild);
  605. }
  606.  
  607. // request and retrieve statistics from API
  608. if (postObj.ids.length > 0) {
  609. sc.api.i = "http://api.worldoftanks."+((wg.srv == "na") ? "com" : wg.srv)+"/wot/account/info/?application_id="+sc.api.wg_key+"&account_id="+postObj.ids.join(',');
  610. sc.api.v = "http://api.worldoftanks."+((wg.srv == "na") ? "com" : wg.srv)+"/wot/account/tanks/?application_id="+sc.api.wg_key+"&account_id="+postObj.ids.join(',');
  611. sf.request(sc.api.i, sf.apiInfoHnd);
  612. }
  613. else {
  614. console.error("No post IDs found or not logged in");
  615. }
  616. }(window));