WoTStatScript - Clanpage

More info for World of Tanks clan page.

当前为 2015-09-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WoTStatScript - Clanpage
  3. // @version 0.9.10.0.4
  4. // @description More info for World of Tanks clan page.
  5. // @author Orrie
  6. // @namespace http://forum.worldoftanks.eu/index.php?/topic/263423-
  7. // @icon http://dl.dropboxusercontent.com/u/12497046/wot/projects/statscript/img/icon.png
  8. // @include http://*.wargaming.net/clans/*/*
  9. // @grant GM_xmlhttpRequest
  10. // @license MIT License
  11. // ==/UserScript==
  12. /*
  13. Changelogs:
  14. Profilepage: http://dl.dropboxusercontent.com/u/12497046/wot/projects/statscript/WoTStatScript-changelog.txt
  15. Clanpage: https://dl.dropboxusercontent.com/u/12497046/wot/projects/statscript/WoTStatScript-Clanpage-changelog.txt
  16. */
  17. (function() {
  18. // global vars
  19. var d = document, c = d.cookie;
  20.  
  21. // get server info and webpage
  22. var wg = {host:d.location.host, href:d.location.href, clan:{}};
  23. wg.srv = wg.host.match(/(eu|ru|na|com|asia|kr)/)[0].replace(/com/,"na");
  24. wg.m = /players\/wot/i.test(wg.href);
  25.  
  26. // getting claninfo
  27. var emblemName = d.getElementsByClassName('page-header_emblem')[0],
  28. clanName = d.getElementsByClassName('clan_name')[0],
  29. sidebarName = d.getElementsByClassName('sidebar-clan_emblem')[0];
  30. wg.clan.id = wg.href.match(/\/(\d+)/)[1];
  31. wg.clan.name = (emblemName || clanName) ? ((clanName) ? clanName.firstElementChild.innerHTML.replace(/[\[\]]/g,"") : emblemName.alt) : sidebarName.alt;
  32. wg.p = new RegExp("\\["+wg.clan.name+"\\] \\|").test(d.title);
  33.  
  34. // script variables
  35. var sc = {
  36. vers: "0.9.10.0.4",
  37. host: "http://gf.qytechs.cn/en/scripts/12137-wotstatscript-clans",
  38. user: "http://forum.wotlabs.net/index.php?/user/1618-orrie/",
  39. top: {
  40. eu: "http://forum.worldoftanks.eu/index.php?showtopic=263423",
  41. na: "http://forum.worldoftanks.com/index.php?showtopic=404652"
  42. },
  43. api: {
  44. ru: "98ca7c4fb108175b67d6505b9c3f3ebd",
  45. eu: "a7595640a90bf2d19065f3f2683b171c",
  46. na: "bf5dba0efd444d75147b6222dd903fd2",
  47. asia: "95f8713eccd322e52dbf521dbd28b19c",
  48. kr: "ffea0f1c3c5f770db09357d94fe6abfb"
  49. },
  50. wn: "http://www.wnefficiency.net/exp/expected_tank_values_latest.json",
  51. loc: c.match(/wgccfe_language=(\w+)/)[1],
  52. locSup: ["en", "ru", "cz", "de", "fr", "pl", "es", "tr"]
  53. };
  54. // script threadlink
  55. sc.link = "<div class='b-scriptlink'><a target='_blank' href="+sc.host+">Script</a> version "+sc.vers+" - <a target='_blank' href="+((wg.srv == "na") ? sc.top.na : sc.top.eu)+">Thread</a></div>";
  56.  
  57. // external site support
  58. var srv = {
  59. wl: false, // wotlabs
  60. nm: false, // noobmeter
  61. ws: false, // wotstats
  62. cs: false, // wotcs
  63. wlife: false, // wot-life
  64. as: false, // away stats
  65. //wn: false, // wot-numbers
  66. //tb: false, // tomatobot
  67. ct: false, // clan tools
  68. aos: false, // age of strife
  69. kttc: false, // kttc
  70. wots: false, // wots
  71. ch: false, // clan history
  72. wr: false // wotreplays
  73. };
  74.  
  75. // determine browser types
  76. var web = {
  77. gecko: typeof InstallTrigger !== 'undefined',
  78. opera: !!window.opera || /opera|opr/i.test(navigator.userAgent),
  79. chrome: !!window.chrome && !!window.chrome.webstore,
  80. safari: /constructor/i.test(window.HTMLElement)
  81. };
  82.  
  83. // fetch wnefficiency values - check if array exists in localStorage, otherwise fetch and reload page
  84. var statObj = {},
  85. wnExpValues = JSON.parse(localStorage.getItem("wnExpValues")),
  86. wnExpDate = JSON.parse(localStorage.getItem("wnExpDate"))+12096e5 >= Date.now(), // true if timestamp is less than 2 weeks old, refresh list if false.
  87. wnExpVers = JSON.parse(localStorage.getItem("wnExpVers")) || "";
  88. if (wnExpVers[0]==sc.vers && wnExpValues && wnExpDate) {
  89. statObj = wnExpValues.data;
  90. }
  91. else {
  92. reqHnd(sc.wn, wnHnd, wnHnd_error);
  93. }
  94.  
  95. // fetch stored clanlist stats - check if array exists in localStorage, otherwise tag fetching to true
  96. var s = {}, statFetch = false,
  97. ssValues = JSON.parse(localStorage.getItem("statScriptValues_"+wg.clan.id)),
  98. ssDate = JSON.parse(localStorage.getItem("statScriptDate_"+wg.clan.id))+6048e5 >= Date.now(); // true if timestamp is less than 1 weeks old, refresh list if false.
  99. if (ssValues && ssDate) {
  100. s = ssValues;
  101. }
  102. else {
  103. statFetch = true;
  104. }
  105.  
  106. // inserting style into head
  107. var style = elem("style", "wotstatscript", "", "text/css");
  108. d.head.appendChild(style);
  109.  
  110. // colour scale array
  111. var colArr = {
  112. // col wr bat sr hr dmg wgr wn8 wn7 eff nm
  113. sUni: [ "#5A3175", 65, 30000, 50, 80, 300, 9900, 2900, 2050, 2050, 2000 ], // 99.99% super unicum
  114. uni: [ "#83579D", 60, 25000, 46, 75, 270, 9000, 2450, 1850, 1800, 1950 ], // 99.90% unicum
  115. gr8: [ "#3972C6", 56, 21000, 42, 70, 240, 8500, 2000, 1550, 1500, 1750 ], // 99.00% great
  116. vGud: [ "#4099BF", 54, 17000, 38, 65, 210, 6500, 1600, 1350 ], // 95.00% very good
  117. good: [ "#4D7326", 52, 13000, 34, 60, 180, 5000, 1200, 1100, 1200, 1450 ], // 82.00% good
  118. aAvg: [ "#849B24", 50, 10000, 30, 55, 150, 4000, 900 ], // 63.00% above average
  119. avg: [ "#CCB800", 48, 7000, 25, 50, 120, 3000, 650, 900, 900, 1250 ], // 40.00% average
  120. bAvg: [ "#CC7A00", 47, 3000, 20, 45, 90, 2000, 450, 700, 600, 1150 ], // 20.00% below average
  121. bas: [ "#CD3333", 46, 1000, 15, 40, 60, 1500, 300, 500 ], // 6.00% basic
  122. beg: [ "#930D0D", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], // 0.00% beginner
  123. dft: [ "#6B6B6B" ], // default
  124. id: { "col": 0, "wr": 1, "bat": 2, "sr": 3, "hr": 4, "dmg": 5, "wgr": 6, "wn8": 7, "wn7": 8, "eff": 9, "nm": 10 } // type identifier
  125. };
  126.  
  127. // localization
  128. // cz-czech - Crabtr33 and Ragnarocek
  129. // de-german - ArtiOpa, Crakker and multimill
  130. // fr-french - SuperPommeDeTerre
  131. // pl-polish - KeluMocy and pokapokami
  132. // es-spanish - Frodo45127
  133. // tr-turkish - Ufuko
  134. // ru-russian - dimon222
  135. var loc = {
  136. // thousands separator
  137. sym: { en: ",", ru: " ", cz: " ", de: ".", fr: " ", pl: " ", es:".", tr: "."},
  138. // clan page
  139. c01: { en: "Clan Stats", ru: "Статистика клана", cz: "Stat. klanu", de: "Clanstatistiken", fr: "Statistiques du clan", pl: "Statystyki klanu", es: "Estadísticas del clan", tr: "Klan İstatistikleri" },
  140. c02: { en: "Replays:", ru: "Реплеи:", cz: "Záznamy:", de: "Replays", fr: "Replays:", pl: "Powtórki:", es: "Repeticiones:", tr: "Replayler" },
  141. // memberlist
  142. c03: { en: "Script Settings", ru: "Script Settings", cz: "Script Settings", de: "Script Settings", fr: "Script Settings", pl: "Script Settings", es:"Script Settings", tr: "Script Settings"},
  143. c04: { en: "Average Winrate", ru: "Average Winrate", cz: "Average Winrate", de: "Average Winrate", fr: "Average Winrate", pl: "Average Winrate", es:"Average Winrate", tr: "Average Winrate"},
  144. c05: { en: "Average WN8", ru: "Average WN8", cz: "Average WN8", de: "Average WN8", fr: "Average WN8", pl: "Average WN8", es:"Average WN8", tr: "Average WN8"}, // Average WN8
  145. c06: { en: "Fetch WN8 for Clan", ru: "Fetch WN8 for Clan", cz: "Fetch WN8 for Clan", de: "Fetch WN8 for Clan", fr: "Fetch WN8 for Clan", pl: "Fetch WN8 for Clan", es:"Fetch WN8 for Clan", tr: "Fetch WN8 for Clan"},
  146. c07: { en: "Fetching WN8 for Clan!", ru: "Fetching WN8 for Clan!", cz: "Fetching WN8 for Clan!", de: "Fetching WN8 for Clan!", fr: "Fetching WN8 for Clan!", pl: "Fetching WN8 for Clan!", es:"Fetching WN8 for Clan!", tr: "Fetching WN8 for Clan!"},
  147. c08: { en: "WN8 Fetched for Clan!", ru: "WN8 Fetched for Clan!", cz: "WN8 Fetched for Clan!", de: "WN8 Fetched for Clan!", fr: "WN8 Fetched for Clan!", pl: "WN8 Fetched for Clan!", es:"WN8 Fetched for Clan!", tr: "WN8 Fetched for Clan!"}
  148. //c00: { en: "", ru: "", cz: "", de: "", fr: "", pl: "", es:"", tr: ""},
  149. };
  150.  
  151. // region settings for external sites
  152. switch(wg.srv) {
  153. case ("eu"): // eu server
  154. srv.wl = srv.nm = srv.ws = srv.cs = srv.wlife = srv.as = srv.wn = srv.tb = srv.ct = srv.kttc = srv.aos = srv.ch = srv.wr = wg.srv;
  155. break;
  156. case ("ru"): // ru server
  157. srv.wl = srv.nm = srv.wn = srv.ws = srv.cs = srv.tb = srv.ct = srv.kttc = srv.wots = srv.aos = srv.ch = srv.wr = wg.srv;
  158. break;
  159. case ("na"): // na server - american english
  160. srv.wl = srv.nm = srv.ws = srv.cs = srv.wlife = srv.wn = srv.tb = srv.ct = srv.kttc = srv.aos = srv.ch = wg.srv; srv.wr = "com"; srv.wn = "us";
  161. break;
  162. case ("asia"): // asia server
  163. srv.wl = srv.nm = srv.wn = srv.ws = srv.cs = "sea"; srv.ct = srv.kttc = srv.aos = srv.ch = wg.srv; srv.wr = "com";
  164. break;
  165. case ("kr"): // korean server
  166. srv.wl = srv.nm = srv.ws = srv.cs = srv.ct = srv.aos = srv.ch = wg.srv; srv.wr = "com";
  167. break;
  168. default: break;
  169. }
  170.  
  171. // set script language to english if an unsupported language is detected
  172. if (sc.locSup.indexOf(sc.loc) == -1) {
  173. sc.loc = "en";
  174. }
  175. // process localization
  176. for (var _l in loc) {
  177. if (loc.hasOwnProperty(_l)) {
  178. loc[_l] = loc[_l][sc.loc];
  179. }
  180. }
  181.  
  182. // add language to body classname for language based styling
  183. d.body.classList.add("lang-"+sc.loc);
  184.  
  185. // variables for dropbox, css and data uri
  186. var css = {
  187. u: {
  188. cIcons: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACACAMAAAA1SxkQAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAADeUExURUxpcTofR0GwyRsZGiIgHyYmJkqkxV1WazJn0f9qAECxyTyqwXAxlhsaGjNly0hTtRERER8dHEq0ynAxlvehhdrhhem/hSwqKhgXFUKwyBkXFEKxyTFlyzAoKHI1lHQron8axT+vxv+GhTJlzP+Chf+AhfR0Wdj9hUOxyf9sAZBKGvVhCv+BhX8axWJUZTFly6DqheicAP/nhf9rAPhrBf9/hfvxhf+phWFoIpNYHdU5LqNdenAxliQjI/9qACEXFjAiISkoKDgrKVBBN0UyMHlMR2tGQqWZlfn5+Xh0a6/IXu8AAAA8dFJOUwAYicrr9hMF/vZU+uiAhjUuqzGBEE4j1mqeVrO3nr1S+tCh04HDQcRvykLwX4b2V9f1s5+A233QvoXq0Fvc5mgAAANrSURBVEjHvZUJc6JMEIabQyaCKCCICGjUGHO4mjv59nM0HGLy///Q9swg6B5VW1tb25UM3c+83dMDIwD8mWny2DCcOnYwNHSw4tNY82PQOAgNQ9aA2IkFX1isY0xY7BM4HyEIDAOVcZKYMDpnEsMIAPpJwjLOzznABTD24QgwgXkAzCQ/8aWTXolE4B9aW4xR1G53Vm1mHJxxax9UUTTlIIrE/WmjD9G0045QtALgs+3VmbbinhBMp6tpxBRnUZlysLJu52B/bzvd1vpg/LZ2q3Dd5YJ6viXus/ArAeGg26kEQwQt7HBYCrprWA9Z7ZFYAi8glKQ1ZE8UawHPQC07Kpi4ZkWZz54tb4mvMhJHoFWBNc8armvQwiU6ot+y9SEpBa3D5rqjaoPl9vnY6n53b3reycki3t1d7xhgfOeBVzO3N/fmMJ/Xad7c9cCd15KXF5wkD15VVLgvL9WiD1zce0Wdx+a8B17Ofe3h/6sLMBHJZLKAxeTiAtxZWX4xcWeX7nPvclY20JstJgQumKhscPZ8eRiFXUyYdvHsVnvgHun9+shIfdsCYsZW9ZOkdICAqn2+rmQn1LYkybKpOmC1cMbs26of922qWBIQhdoDdbnfZw01oaoNlkobjeQz+/xMVJUqJtgULUmzfcYcWwKTXWn6uUw4IGApXJKlfAIXJgPMVJSlryjosN4kE0v1zT4uXXbGkhppA9c0xTuEWCaqsYWBVL1NrL5iDqxfvFNitXFkagwqPbIkUaFxHC+X/gnwh//fCJDwjaiDp+Y1B0mWsYt5ebtpcuC/vQ0Uqtxcb0pgPt0+3bz997gpAZtqXt/fN0uAtdDb3N9vOFBojLUqa8JNzHNrcP31a/MENG+PEjjYbE7BY/PEHn/vY/K9K9eAuY4mV58aJ9Ac/Ppo4zJJGzs4qcuBHnKihXog6yDLV8FVyH5JITqyDA5KnFAjBBNQgDWuglAPQQ4AL8EVS9ZlWdfCUGNX8aw1WZd1/JOd6nGTMSFj7bh7h3X4u69TSdnimRcjN2W73dJy5LZlVo7cVO6qNUCfVuNP7b02jMx3eE/TdJ+nAtg4pHmef+wzxO+gMppnWfaBJE9Tng5ZURQfSPI8BZSlUOx2O4yLLM8hZ3THwL4osiwHX4CiwBhBBlJcKnaMIsA+0h8a/QZnvrDP+ki71wAAAABJRU5ErkJggg==",
  189. arrow: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAECAMAAAB1GNVPAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAPUExURf///////////0xpcf///17pIXYAAAAEdFJOU393iAAiK7rGAAAAH0lEQVQI1w3GwQEAMBBEQBf6rzn7YeipxA0bXoU4LB8EgABGoTqNxwAAAABJRU5ErkJggg=="
  190. }
  191. };
  192.  
  193. // style contents
  194. var styleClan = [
  195. // script header rules
  196. "#common_menu .cm-menu__user > *:not(.cm-notifications) {display: inline-block}",
  197. "#common_menu .b-scriptlink a {color: #E5B12E;}",
  198. "#common_menu .b-scriptlink a:hover {color: #FFBE4C; text-shadow: 0px 0px 7px rgba(255, 126, 0, 0.7);}",
  199. "#common_menu .b-login-msg:hover, #common_menu .b-scriptlink:hover {color: #707273; cursor: initial;}",
  200. "#common_menu .cm-link__get-gold {margin: 0 12px;}",
  201. ".profile__main {margin: 0; padding: 0;}",
  202. // links menu rules
  203. ".menu-clan_links {padding: 0;}",
  204. ".menu-clan_links.cm-parent-link__opened {border: 1px solid #313335;}",
  205. ".menu-clan_links .menu-top_link {cursor: pointer; padding: 0 8px 0 9px;}",
  206. ".menu-clan_links .menu-top_link.cm-parent-link__opened {background: #0E0E0E; border-left: 1px solid #313335; border-right: 1px solid #313335; margin-left: -1px;}",
  207. ".menu-clan_links .cm-arrow {background-image: url('"+css.u.arrow+"'); display: inline-block; margin-left: 5px; opacity: 0.5; vertical-align: middle; transition: opacity 0.2s ease 0s; height: 4px; width: 7px;}",
  208. ".menu-clan_links .cm-parent-link__opened .cm-arrow {opacity: 1; transform: rotate(180deg);}",
  209. ".menu-clan_links .clan-links {background: rgba(14, 14, 14, 0.99); border: 1px solid #313335; display: none; box-shadow: 0px 0px 25px rgba(0, 0, 0, 0.4); margin-left: -1px; padding: 14px 16px;}",
  210. ".menu-clan_links .cm-sublist__opened {display: block;}",
  211. ".menu-clan_links .clan-links td {padding: 0 10px;}",
  212. ".sl-icon {background: url('"+css.u.cIcons+"') no-repeat; display: inline-block; margin: -2px 8px 0px 0px; vertical-align: middle; height: 16px; width: 16px;}",
  213. ".sl-wl {background-position: 0px 0px;}",
  214. ".sl-nm {background-position: 0px -16px;}",
  215. ".sl-ct {background-position: 0px -32px;}",
  216. ".sl-cs {background-position: 0px -48px;}",
  217. ".sl-kttc {background-position: 0px -64px;}",
  218. ".sl-wlife {background-position: 0px -80px;}",
  219. ".sl-as {background-position: 0px -96px;}",
  220. ".sl-wr {background-position: 0px -112px;}",
  221. // rating profile rules
  222. ".rating-profile {width: 70%; margin: 0px auto;}",
  223. // settings menu rules
  224. "#common_menu .menu-settings label {display: block; text-align: left;}",
  225. "#common_menu .menu-settings .l-box {margin: 0 5px 1px 0; vertical-align: middle;}",
  226. "#common_menu .menu-settings .l-text {color: #BABDBF; vertical-align: middle;}",
  227. "#common_menu .menu-settings textarea.l-textarea {text-align: left; line-height: normal; padding: 5px;}",
  228. // memberpage rules
  229. ".page-header {padding: 30px 0 30px 0}",
  230. // button fetch rules
  231. ".b-button-stats {border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 2px 0px 0px 2px; position: absolute; right: 0; top: 9px;}",
  232. ".b-button-stats a {background: rgba(255, 255, 255, 0.1); color: #FFFFFF; cursor: pointer; font-size: 17px; line-height: 45px; display: block; padding: 0px 15px; transition: all 0.2s ease 0s;}",
  233. ".b-button-stats a:hover {background: rgba(229, 177, 46, 0.25);}",
  234. // rating players rules
  235. ".rating-players {height: 200px;}",
  236. ".rating-players tbody {width: 70%; display: table; margin: 0px auto;}",
  237. ".rating-players_item__data {padding-top: 15px}",
  238. ".rating-players_item__average {padding-top: 10px}",
  239. ".rating-players_stats {font-size: 40px;}",
  240. // membertable rules
  241. "#js-playerslist-table {margin-top: -40px;}",
  242. ".rating-table_wn a {cursor: pointer;}",
  243. ""
  244. ];
  245. style.textContent = styleClan.join("");
  246. // end style
  247.  
  248. // script link
  249. var clanHead_div = elem("div", "cm-parent-link", sc.link),
  250. navMenu = d.getElementById('common_menu'),
  251. navUser = navMenu.getElementsByClassName('cm-menu__user')[0];
  252. // add script info if user menu exists, else wait
  253. if (navUser) {
  254. navUser.insertBefore(clanHead_div, navUser.firstChild);
  255. }
  256. else {
  257. var navLook = new MutationObserver(function() {
  258. navUser = navMenu.getElementsByClassName('cm-menu__user')[0];
  259. navUser.insertBefore(clanHead_div, navUser.firstChild);
  260. navLook.disconnect();
  261. });
  262. navLook.observe(navMenu, {childList: true});
  263. }
  264.  
  265. // clan statistic links
  266. var menu_class = d.getElementsByClassName('menu-top')[0],
  267. clanMenu_div = elem("div", "menu-clan_links menu-top_item", "<span class='menu-top_link'>"+loc.c01+"<span class='cm-arrow'></span></span>"),
  268. clanMenu_list = elem("ul", "clan-links cm-sublist", ""),
  269. clanMenu_list_items = [
  270. [srv.wl, "<a target='_blank' href='http://wotlabs.net/"+srv.wl+"/clan/"+wg.clan.name+"'><span class='sl-icon sl-wl'></span>WoTLabs</a>"],
  271. [srv.nm, "<a target='_blank' href='http://noobmeter.com/clan/"+srv.nm+"/"+wg.clan.name+"/"+wg.clan.id+"'><span class='sl-icon sl-nm'></span>Noobmeter</a>"],
  272. [srv.ct, "<a target='_blank' href='https://clantools.us/servers/"+srv.ct+"/clans?id="+wg.clan.id+"'><span class='sl-icon sl-ct'></span>Clan Tools</a>"],
  273. [srv.cs, "<a target='_blank' href='http://wotcs.com/clan.php?wid="+wg.clan.id+"'><span class='sl-icon sl-cs'></span>WoT-CS</a>"],
  274. [srv.kttc, "<a target='_blank' href='http://"+((wg.srv=="ru") ? "" : srv.kttc+".")+"kttc.ru/clan/"+wg.clan.id+"/'><span class='sl-icon sl-kttc'></span>KTTC</a>"],
  275. [srv.wlife, "<a target='_blank' href='http://en.wot-life.com/"+srv.wlife+"/clan/"+wg.clan.name+"-"+wg.clan.id+"/'><span class='sl-icon sl-wlife'></span>WoT-Life</a>"],
  276. [srv.as, "<a target='_blank' href='http://stats.teamaway.net/clan/"+wg.clan.id+"/'><span class='sl-icon sl-as'></span>AWAY Stats</a>"],
  277. [srv.wr, "<a target='_blank' href='http://wotreplays."+srv.wr+"/clan/"+wg.clan.name+"'><span class='sl-icon sl-wr'></span>WoTReplays</a>"]
  278. ];
  279. linksHnd(clanMenu_list, clanMenu_list_items);
  280. clanMenu_div.firstElementChild.addEventListener('click', function() {this.classList.toggle('cm-parent-link__opened'); this.nextSibling.classList.toggle('cm-sublist__opened');}, false);
  281. clanMenu_div.appendChild(clanMenu_list);
  282. menu_class.appendChild(clanMenu_div);
  283.  
  284. // add clan total stats if they exist
  285. if (wg.p && s.clan) {
  286. var clanStatValue = d.getElementsByClassName('rating-profile_item');
  287. if (s.clan.win) {
  288. clanStatValue[1].innerHTML = "<i class='rating-profile_icon i i__rating-common i__wot-victories'></i><span class='rating-profile_value rating-players_stats js-format-number'>"+colStat(s.clan.win, "wr", 2, "%")+"</span><span class='rating-profile_key'>Average Winrate</span>";
  289. }
  290. if (s.clan.wn8) {
  291. clanStatValue[3].innerHTML = "<i class='rating-profile_icon i i__rating-common i__wot-experience'></i><span class='rating-profile_value rating-players_stats js-format-number'>"+colStat(s.clan.wn8,"wn8",0)+"</span><span class='rating-profile_key'>Average WN8</span>";
  292. }
  293. }
  294.  
  295. // check if on memberlist page
  296. if (wg.m) {
  297. // formula calculations and variables
  298. var memObj = {
  299. cls: d.getElementsByClassName('rating-table_body')[0],
  300. ids: [],
  301. num: []
  302. };
  303. // memberlist settings
  304. var clanSet_div = elem("div", "menu-settings menu-top_item", "<span class='cm-parent-link js-cm-dropdown-link'>"+loc.c03+"<span class='cm-arrow'></span></span>"),
  305. clanSet_list = elem("ul", "cm-sublist", ""),
  306. enableOnPageload = JSON.parse(localStorage.getItem("statScript_onPageload")),
  307. enableWhitelist = JSON.parse(localStorage.getItem("statScript_whitelist")),
  308. enableWhiteListList = localStorage.getItem("statScript_whitelist_list"),
  309. whiteListArray = (enableWhiteListList) ? enableWhiteListList.split(",") : "",
  310. clanSet_list_items = [
  311. optionHnd("onPageload", "Load Stats Automatically", enableOnPageload, false),
  312. optionHnd("whitelist", "Use Whitelist", enableWhitelist, false, enableWhiteListList)
  313. ];
  314. linksHnd(clanSet_list, clanSet_list_items);
  315. clanSet_div.firstElementChild.addEventListener('click', function() {this.classList.toggle('cm-parent-link__opened'); this.nextSibling.classList.toggle('cm-sublist__opened');}, false);
  316. clanSet_div.appendChild(clanSet_list);
  317. // add script settings if user menu exists, else wait
  318. if (navUser) {
  319. navUser.insertBefore(clanSet_div, navUser.firstChild);
  320. }
  321. else {
  322. var setLook = new MutationObserver(function() {
  323. navUser = navMenu.getElementsByClassName('cm-menu__user')[0];
  324. navUser.insertBefore(clanSet_div, navUser.firstChild);
  325. setLook.disconnect();
  326. });
  327. setLook.observe(navMenu, {childList: true});
  328. }
  329.  
  330. // prepare stat fetcher, store stats in localStorage and reload page
  331. var ratLook = new MutationObserver(function() {
  332. tableFetch();
  333. ratLook.disconnect();
  334. });
  335.  
  336. // add manual stat fetching button
  337. var timeFrame_class = d.getElementsByClassName('timeframe')[0],
  338. refreshBtn_div = elem("div", "b-button-stats", "<a id='js-wn8-fetch'>"+loc.c06+"</a>");
  339. refreshBtn_div.addEventListener('click', function() {this.firstElementChild.textContent = loc.c07; tableFetch();}, false);
  340. timeFrame_class.appendChild(refreshBtn_div);
  341.  
  342. // fetch stats automatically if enabled or check whitelist for whitelisted clan
  343. if (statFetch && (enableOnPageload || (enableWhitelist && whiteListArray.indexOf(wg.clan.id) > -1))) {
  344. ratLook.observe(memObj.cls, {childList: true});
  345. }
  346. else {
  347. // wait for table to be filled before adding wn8
  348. var clanInsertStatus = false, ratHeadStatus = false,
  349. ratHead = d.getElementsByClassName('rating-table_head')[0].rows[0],
  350. ratInsert = new MutationObserver(function(muto) {
  351. if (muto[0].previousSibling === null) {
  352. // add clan total stats if they exist
  353. if (s.clan && clanInsertStatus === false) {
  354. var clanStatValue = d.getElementsByClassName('rating-players_item');
  355. if (s.clan.win) {
  356. clanStatValue[1].innerHTML = "<i class='rating-players_icon i i__rating-common i__wot-victories'></i><span class='rating-players_value rating-players_stats'>"+colStat(s.clan.win, "wr", 2, "%")+"</span><span class='rating-players_key'>"+loc.c04+"</span>";
  357. }
  358. if (s.clan.wn8) {
  359. clanStatValue[3].innerHTML = "<i class='rating-players_icon i i__rating-common i__wot-experience'></i><span class='rating-players_value rating-players_stats'>"+colStat(s.clan.wn8,"wn8",0)+"</span><span class='rating-players_key'>"+loc.c05+"</span>";
  360. }
  361. clanInsertStatus = true;
  362. }
  363. // table header for wn8
  364. if (ratHeadStatus === false && Object.keys(s).length != 0) {
  365. var wnHead = ratHead.insertCell((ratHead.childElementCount == 14) ? 4 : 3);
  366. wnHead.className = "rating-table_th rating-table_th__key rating-table_wn";
  367. wnHead.innerHTML = "<a class='table-sorter js-tooltip js-tooltip-id_js-pr-tooltip js-table-sorter js-sort-wn'><i class='table-sorter_icon table-sorter_icon__media i i__table-params i__wot-aeb'></i><span class='table-sorter_key'>WN8</span></a>";
  368. ratHeadStatus = true;
  369. }
  370. // add wn8 for each member
  371. for (var _rt=0, _rt_len = memObj.cls.rows.length; _rt<_rt_len; _rt++) {
  372. var row = memObj.cls.rows[_rt],
  373. id = row.getAttribute('data-account_id'),
  374. wnRow = row.insertCell((ratHead.childElementCount == 14) ? 3 : 4);
  375. wnRow.className = "rating-table_td rating-table_td__value js-account-500171710-stats js-format-number";
  376. wnRow.innerHTML += s[id].wn8;
  377. }
  378. }
  379. });
  380. ratInsert.observe(memObj.cls, {childList: true});
  381. }
  382. }
  383.  
  384. function tableFetch() {
  385. // find required info from table player rows
  386. for (var _rt=0, _rt_len = memObj.cls.rows.length; _rt<_rt_len; _rt++) {
  387. var id = memObj.cls.rows[_rt].getAttribute('data-account_id'),
  388. name = memObj.cls.rows[_rt].getElementsByClassName('player_name')[0].innerHTML.match(/[\w\_]+/)[0];
  389. if (!isNaN(id)) {
  390. var users = memObj.ids.length,
  391. index = memObj.ids.indexOf(id);
  392. s[id] = {u:{name:name,id:id}, v:{frag:0,dmg:0,spot:0,def:0,win:0}, wn8:""};
  393. if (index>-1) {
  394. memObj.num[index][memObj.num[index].length] = _rt;
  395. }
  396. else {
  397. memObj.ids[users] = id;
  398. memObj.num[users] = [_rt];
  399. }
  400. }
  401. }
  402. s.clan = {wn8:0, win:0, mem: memObj.ids.length};
  403. // request and retrieve statistics from API
  404. if (memObj.ids.length > 0) {
  405. sc.api.i = "http://api.worldoftanks."+((wg.srv == "na") ? "com" : wg.srv)+"/wot/account/info/?application_id="+sc.api[wg.srv]+"&account_id="+memObj.ids.join(',');
  406. sc.api.v = "http://api.worldoftanks."+((wg.srv == "na") ? "com" : wg.srv)+"/wot/account/tanks/?application_id="+sc.api[wg.srv]+"&account_id="+memObj.ids.join(',');
  407. reqHnd(sc.api.i, apiInfoHnd);
  408. }
  409. }
  410.  
  411. // processing information from player API
  412. function apiInfoHnd(resp) {
  413. var data = JSON.parse(resp).data;
  414. for (var a in data) {
  415. if (data.hasOwnProperty(a)) {
  416. var pData = data[a];
  417. if (pData !== null) {
  418. // store stats
  419. s[pData.account_id].u = {
  420. name: pData.nickname,
  421. id: pData.account_id,
  422. cid: pData.clan_id,
  423. bat: pData.statistics.all.battles,
  424. win: (pData.statistics.all.wins/pData.statistics.all.battles)*100,
  425. dmg: pData.statistics.all.damage_dealt/pData.statistics.all.battles,
  426. frag: pData.statistics.all.frags/pData.statistics.all.battles,
  427. spot: pData.statistics.all.spotted/pData.statistics.all.battles,
  428. def: pData.statistics.all.dropped_capture_points/pData.statistics.all.battles,
  429. wgr: pData.global_rating,
  430. lng: pData.client_language
  431. };
  432. s.clan.win += (!isNaN(s[pData.account_id].u.win)) ? s[pData.account_id].u.win : 0;
  433. }
  434. }
  435. }
  436. reqHnd(sc.api.v, apiVehHnd);
  437. }
  438.  
  439. // processing information from vehicle API and calculate WN8
  440. function apiVehHnd(resp) {
  441. var data = JSON.parse(resp).data;
  442. for (var p in data) {
  443. if (data.hasOwnProperty(p)) {
  444. var vData = data[p];
  445. if (vData !== null) {
  446. var rWin, rDmg, rFrag, rSpot, rDef, wn8 = 0;
  447. if (s[p].u.bat > 0) {
  448. for (var v in vData) {
  449. if (vData.hasOwnProperty(v)) {
  450. // go through each vehicle to get expected stats
  451. for (var _so=0, _so_len = statObj.length; _so<_so_len; _so++) {
  452. if (statObj[_so].IDNum == vData[v].tank_id) {
  453. var vehStat = statObj[_so],
  454. dataBattles = vData[v].statistics.battles;
  455. s[p].v.frag += vehStat.expFrag * dataBattles;
  456. s[p].v.dmg += vehStat.expDamage * dataBattles;
  457. s[p].v.spot += vehStat.expSpot * dataBattles;
  458. s[p].v.def += vehStat.expDef * dataBattles;
  459. s[p].v.win += vehStat.expWinRate * dataBattles;
  460. break;
  461. }
  462. }
  463. }
  464. }
  465. // start calculating wn8
  466. rWin = Math.max(((s[p].u.win /(s[p].v.win /s[p].u.bat)-0.71)/(1-0.71)),0);
  467. rDmg = Math.max(((s[p].u.dmg /(s[p].v.dmg /s[p].u.bat)-0.22)/(1-0.22)),0);
  468. rFrag = Math.max(Math.min(rDmg+0.2,((s[p].u.frag/(s[p].v.frag/s[p].u.bat)-0.12)/(1-0.12))),0);
  469. rSpot = Math.max(Math.min(rDmg+0.1,((s[p].u.spot/(s[p].v.spot/s[p].u.bat)-0.38)/(1-0.38))),0);
  470. rDef = Math.max(Math.min(rDmg+0.1,((s[p].u.def /(s[p].v.def /s[p].u.bat)-0.10)/(1-0.10))),0);
  471. wn8 = 980*rDmg + 210*rDmg*rFrag + 155*rFrag*rSpot + 75*rDef*rFrag + 145*Math.min(1.8,rWin);
  472. }
  473. // store wn8 and add to clan total
  474. s[p].wn8 = colStat(wn8,"wn8",0);
  475. s.clan.wn8 += wn8;
  476. d.getElementById('js-wn8-fetch').textContent = loc.c08;
  477. }
  478. }
  479. }
  480. // calculate average wn8 / winrate and store everything in localStorage, then reload page
  481. s.clan.wn8 = s.clan.wn8/s.clan.mem;
  482. s.clan.win = s.clan.win/s.clan.mem;
  483. localStorage.setItem("statScriptValues_"+wg.clan.id, JSON.stringify(s));
  484. localStorage.setItem("statScriptDate_"+wg.clan.id, Date.now());
  485. location.reload();
  486. }
  487.  
  488. // helper functions
  489. // filter
  490. function filter(input, type) {
  491. var inputStr = input.toString();
  492. switch(type) {
  493. case (1): // input string into number
  494. return parseFloat(inputStr.replace(/[^\d]/g,""));
  495. case (2): // output number with locale symbol
  496. return inputStr.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1"+loc.sym);
  497. case (3): // remove all symbols
  498. return inputStr.replace(/[^\w]/g,"");
  499. default:
  500. console.error("Error filtering: ", input);
  501. return input;
  502. }
  503. }
  504.  
  505. // colouring
  506. function colStat(input, type, dec, sym) {
  507. var color = colArr.dft[0],
  508. output = input.toFixed(dec);
  509. if (sym) {
  510. output += sym;
  511. }
  512. if (input >= 1000) {
  513. output = input.toFixed(dec).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1"+loc.sym);
  514. }
  515. for (var c in colArr) {
  516. if (colArr.hasOwnProperty(c)) {
  517. if (input >= colArr[c][colArr.id[type]]) {
  518. color = colArr[c][0]; break;
  519. }
  520. }
  521. }
  522. return "<font color='"+color+"'>"+output+"</font>";
  523. }
  524.  
  525. // quick creation of element
  526. function elem(tag, name, html, type) {
  527. var element = d.createElement(tag);
  528. if (name) {
  529. element.className = name;
  530. }
  531. if (html) {
  532. if (/</.test(html)) {
  533. element.innerHTML = html;
  534. }
  535. else {
  536. element.textContent = html;
  537. }
  538. }
  539. if (type) {
  540. element.type = type;
  541. }
  542. return element;
  543. }
  544.  
  545. // option handler
  546. function optionHnd(name, text, state, dftState, wlist) {
  547. var listItem = elem("li", "settingItem", ""),
  548. optLabel = elem("label", "l-label", ""),
  549. optCheck = elem("input", "l-box", "", "checkbox"),
  550. optDesc = elem("span", "l-text", text);
  551. optCheck.name = name;
  552. optCheck.checked = (state !== undefined) ? state : dftState;
  553. optCheck.addEventListener('click', function() {
  554. var clickBox = this;
  555. localStorage.setItem('statScript_' + clickBox.name, clickBox.checked);
  556. d[clickBox.name] = clickBox.checked;
  557. return clickBox.checked;
  558. }, false);
  559. d[optCheck.name] = optCheck.checked;
  560. optLabel.appendChild(optCheck);
  561. optLabel.appendChild(optDesc);
  562. listItem.appendChild(optLabel);
  563. if (name == "whitelist") {
  564. var optText = elem("textarea", "l-textarea", "");
  565. optText.placeholder = "Add clanID seperated by comma without spaces: 500004502,500010805";
  566. if (wlist) {
  567. optText.value = wlist;
  568. }
  569. optText.addEventListener('input', function() {
  570. localStorage.setItem('statScript_whitelist_list', optText.value.split(","));
  571. }, false);
  572. listItem.appendChild(optText);
  573. }
  574. return listItem;
  575. }
  576.  
  577. // links handler
  578. function linksHnd(parent, links) {
  579. var uRows = d.createDocumentFragment();
  580. for (var _l=0, _l_len = links.length; _l<_l_len; ++_l) {
  581. if (links[_l] instanceof HTMLElement) {
  582. uRows.appendChild(links[_l]);
  583. }
  584. else {
  585. uRows.appendChild((links[_l][0] && links[_l][1]) ? elem("li", "", links[_l][1]) : elem("li", "statname", links[_l][0]));
  586. }
  587. }
  588. parent.appendChild(uRows);
  589. }
  590. // end helper functions
  591.  
  592. // wnefficiency handler
  593. function wnHnd(resp) {
  594. localStorage.setItem("wnExpValues", resp);
  595. localStorage.setItem("wnExpDate", Date.now());
  596. localStorage.setItem("wnExpVers", JSON.stringify([sc.vers, JSON.parse(resp).header.version]));
  597. location.reload();
  598. }
  599. function wnHnd_error(error) {
  600. console.error("Error accessing WNEfficiency.net", error);
  601. }
  602. // end wnefficiency handler
  603.  
  604. // retrieval function
  605. function reqHnd(url, handler, error) {
  606. GM_xmlhttpRequest({
  607. method: "GET",
  608. url: url,
  609. headers: {
  610. "Accept": "text/xml"
  611. },
  612. onload: function(resp) {
  613. if (resp.readyState == 4 && resp.status == 200 && resp.statusText == "OK") {
  614. handler(resp.responseText);
  615. }
  616. else {
  617. error(resp.responseText);
  618. }
  619. },
  620. onerror: function(resp) {
  621. error(resp.responseText);
  622. }
  623. });
  624. }
  625. }(window));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址