Tidy up your Dashboard

Tidy Up Your Dashboard is a Userscript which brings along a lot of features for improving the user experience on Warzone.

  1. // ==UserScript==
  2. // @name Tidy up your Dashboard
  3. // @namespace https://gf.qytechs.cn/users/10154
  4. // @grant none
  5. // @run-at document-start
  6. // @match https://www.warzone.com/*
  7. // @description Tidy Up Your Dashboard is a Userscript which brings along a lot of features for improving the user experience on Warzone.
  8. // @version 3.4.4
  9. // @icon http://i.imgur.com/XzA5qMO.png
  10. // @require https://code.jquery.com/jquery-1.11.2.min.js
  11. // @require https://code.jquery.com/ui/1.11.3/jquery-ui.min.js
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js
  13. // @require https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/dataTables.bootstrap.min.js
  14. // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js
  15. // ==/UserScript==
  16. window.timeUserscriptStart = new Date().getTime();
  17. window.MULIS_USERSCRIPT = true;
  18. var version = GM_info.script.version;
  19. this.$$$ = jQuery.noConflict(true);
  20. window.wlerror = function () {
  21. };
  22. setupImages();
  23.  
  24. console.log("Running Muli's userscript");
  25. if (pageIsDashboard()) {
  26. createSelector(".container-fluid", "display: none");
  27. createSelector("body", "overflow: hidden")
  28. }
  29.  
  30. setupDatabase();
  31. log("indexedDB setup complete");
  32.  
  33. if (document.readyState === 'complete' || document.readyState === 'interactive') {
  34. log("Readystate complete|interactive");
  35.  
  36. DOM_ContentReady();
  37. } else {
  38. window.document.addEventListener("DOMContentLoaded", DOM_ContentReady);
  39. log("Readystate loading")
  40. }
  41.  
  42.  
  43. function removePlayerDataCookie() {
  44. $.removeCookie("muli_wl_player");
  45. }
  46. function loadPlayerData() {
  47. let cookieValue = $.cookie('muli_wl_player');
  48. if (cookieValue) {
  49. window.WlPlayer = JSON.parse(cookieValue);
  50. log("Skipping reloading player data " + $.cookie('wlPlayerCacheValid'));
  51. return;
  52. }
  53. let player = {
  54. Name: null,
  55. PlayerId: null,
  56. ProfileId: null,
  57. ProfileToken: [],
  58. isMember: null,
  59. OnVacationUntil: null,
  60. Level: null,
  61. PointsThisLevel: null
  62. }
  63. let profileUrl = "https://www.warzone.com" + $(".dropdown-menu a[href*='Profile']").attr('href');
  64. $.ajax({
  65. url: profileUrl,
  66. async: false,
  67. success: function (response) {
  68. let page = $(response);
  69. player.Name = page.find("#AccountDropDown").text().trim();
  70. player.PlayerId = extractPlayerId(profileUrl);
  71. player.ProfileId = extractProfileId(profileUrl);
  72. player.ProfileToken = extractProfileToken(profileUrl);
  73. player.isMember = page.find("#MemberIcon").length > 0;
  74. player.OnVacationUntil = getVacationEndDate(page);
  75. player.Level = page.find("#LevelLink").text().trim().replace("L", "")
  76. player.PointsThisLevel = Number(page.find("#LevelLink").attr("title").match(/Progress to next:\s*([\d,]+)/)[1].replace(/[^\d]/g, ''));
  77.  
  78. window.WlPlayer = player;
  79.  
  80. // Create a cookie to cache the values for 1 hour
  81. $.cookie("muli_wl_player", JSON.stringify(player), { expires: new Date(new Date().getTime() + 1 * 60 * 60 * 1000) });
  82. }
  83. });
  84. }
  85.  
  86. function getVacationEndDate(page) {
  87. let vacationText = page.find("img[src*='Vacation']")
  88. .parent()
  89. .contents()
  90. .filter(function () {
  91. if (this.nodeType === 3) {
  92. return this.nodeValue.includes("vacation")
  93. }
  94. return false;
  95. })
  96. .text()
  97. .trim();
  98. let match = vacationText.match(/(\d{1,2}\/\d{1,2}\/\d{4} \d{2}:\d{2}:\d{2})/);
  99.  
  100. if (match) {
  101. return new Date(match[1]);
  102. }
  103. return null;
  104. }
  105.  
  106. /**
  107. * Extracts the full id of a player. The player id is built as following:
  108. * - first 2 digits of the profile token
  109. * - the profile id
  110. * - last 2 digits of the profile token
  111. */
  112. function extractPlayerId(url) {
  113. let match = url.match(/p=(\d+)/);
  114. if (match != null) {
  115. return match[1];
  116. }
  117. return null;
  118. }
  119.  
  120.  
  121. function extractProfileId(url) {
  122. let match = url.match(/p=(\d+)/);
  123. if (match != null) {
  124. return match[1].slice(2, -2);
  125. }
  126. return null;
  127. }
  128.  
  129. function extractProfileToken(url) {
  130. let match = url.match(/p=(\d+)/);
  131. if (match != null) {
  132. return [match[1].slice(0, 2), match[1].slice(-2)];
  133. }
  134. return null;
  135. }
  136.  
  137. wljs_WaitDialogJS = {
  138. Start: () => { },
  139. Stop: () => { }
  140. }
  141. var logData = "";
  142.  
  143. function log(entry) {
  144. var time = moment(new Date()).format('h:mm:ss');
  145. logData += `\n${time} | ${entry}`;
  146. }
  147.  
  148. function logError(entry) {
  149. var time = moment(new Date()).format('h:mm:ss');
  150. logData += `\n${time} | ${entry}`;
  151. }
  152.  
  153. //ctrl+shift+2
  154. $$$(document).keydown(function (e) {
  155. if (e.which === 50 && e.ctrlKey && e.shiftKey) {
  156. getLog()
  157. }
  158. });
  159.  
  160. window.logDialog = undefined;
  161. window.getLog = function () {
  162. if (logDialog) {
  163. logDialog.html(`<textarea style="height:100%;width:100%">${logData}</textarea>`);
  164. logDialog.dialog('open')
  165. } else {
  166. logDialog = $$$(`<div style="overflow:hidden"><textarea style="height:100%;width:100%">${logData}</textarea></div>`).dialog({
  167. width: 800,
  168. title: "Userscript log",
  169. height: 400
  170. });
  171. }
  172. };
  173. window.onerror = windowError;
  174.  
  175. function windowError(message, source, lineno, colno, error) {
  176. logError(`Error on line ${lineno} col ${colno} in ${source}`);
  177. logError(`${JSON.stringify(error)} ${message}`);
  178.  
  179. if (typeof $().dialog == "function") {
  180. window.wlerror(message, source, lineno, colno, error)
  181. }
  182. }
  183. window.mtlRatingCache = {};
  184.  
  185. function loadMtlPlayer(playerId) {
  186. var cachedRating = mtlRatingCache[playerId];
  187. if (cachedRating != undefined) {
  188. return $.Deferred().resolve({ data: JSON.stringify({ player: { displayed_rating: cachedRating } }) });
  189. }
  190. var urlParam = "https://warlight-mtl.com/api/v1.0/players/" + playerId;
  191. var url = "https://maak.ch/wl/httpTohttps.php?url=" + encodeURI(urlParam);
  192. return $.ajax({
  193. type: 'GET',
  194. url: url,
  195. dataType: 'jsonp',
  196. crossDomain: true,
  197. timeout: 9000,
  198. });
  199. }
  200.  
  201. function setupMtlProfile() {
  202. var playerId = location.href.match(/p=(\d+)/)[1];
  203. var urlParam = "https://warlight-mtl.com/api/v1.0/players/" + playerId;
  204. var url = "https://maak.ch/wl/httpTohttps.php?url=" + encodeURI(urlParam);
  205. $.ajax({
  206. type: 'GET',
  207. url: url,
  208. dataType: 'jsonp',
  209. crossDomain: true
  210. }).done(function (response) {
  211. var data = JSON.parse(response.data);
  212. var player = data.player;
  213. if (player) {
  214. var mdlStats = '<td><a target="_blank" href="https://warlight-mtl.com/player?playerId=' + playerId + '">MDL</a></td>';
  215. if (player.rank) {
  216. mdlStats += '<td>' + getRankText(player.best_rank) + ' (' + player.best_displayed_rating + ')</td><td>' + getRankText(player.rank) + ' (' + player.displayed_rating + ')</td>'
  217. } else if (player.best_displayed_rating) {
  218. mdlStats += `<td> ${getRankText(player.best_rank)} (${player.best_displayed_rating}) </td><td> Unranked (${player.displayed_rating}) </td>`;
  219. } else if (player.displayed_rating) {
  220. mdlStats += `<td></td><td> Unranked (${player.displayed_rating}) </td>`;
  221. }
  222. } else {
  223. var mdlStats = '<td><a target="_blank" href="https://warlight-mtl.com/">MDL</a></td>';
  224. mdlStats += '<td colspan="2">Currently not participating </td>'
  225. }
  226. $("h3:contains('Ladders')").next().find("table tbody").prepend('<tr>' + mdlStats + '</tr>');
  227. })
  228. }
  229.  
  230. function setupMtlLadderTable() {
  231. addCSS(`
  232. .spinner {
  233. margin: 100px auto 0;
  234. width: 70px;
  235. text-align: center;
  236. }
  237.  
  238. .spinner > div {
  239. width: 18px;
  240. height: 18px;
  241. background-color: #333;
  242.  
  243. border-radius: 100%;
  244. display: inline-block;
  245. -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
  246. animation: sk-bouncedelay 1.4s infinite ease-in-out both;
  247. }
  248.  
  249. .spinner .bounce1 {
  250. -webkit-animation-delay: -0.32s;
  251. animation-delay: -0.32s;
  252. }
  253.  
  254. .spinner .bounce2 {
  255. -webkit-animation-delay: -0.16s;
  256. animation-delay: -0.16s;
  257. }
  258.  
  259. @-webkit-keyframes sk-bouncedelay {
  260. 0%, 80%, 100% { -webkit-transform: scale(0) }
  261. 40% { -webkit-transform: scale(1.0) }
  262. }
  263.  
  264. @keyframes sk-bouncedelay {
  265. 0%, 80%, 100% {
  266. -webkit-transform: scale(0);
  267. transform: scale(0);
  268. } 40% {
  269. -webkit-transform: scale(1.0);
  270. transform: scale(1.0);
  271. }
  272. }
  273. `);
  274. var mtlData = `
  275. <section class="container" id="mtlData">
  276. <div class="p-3">
  277. <div class="row bg-gray p-3 br-4">
  278. <div class="mdlPlayers p-3 " style="flex:1">
  279. <div class="spinner mdlPlayerTable-loading" style="min-width:265px">
  280. <div class="bounce1"></div>
  281. <div class="bounce2"></div>
  282. <div class="bounce3"></div>
  283. </div>
  284. <div class="mdl-content" style="display:none">
  285. <a href="https://warlight-mtl.com/allplayers" style="float:right;margin-top:5px">Show All</a>
  286. </div>
  287. </div>
  288. <div class="mdlGames p-3 " style="flex:1">
  289. <div class="spinner mdlGamesTable-loading">
  290. <div class="bounce1"></div>
  291. <div class="bounce2"></div>
  292. <div class="bounce3"></div>
  293. </div>
  294. </div>
  295. </div>
  296. </div>
  297. </section>`;
  298. $(".container:nth-of-type(1)").after(mtlData);
  299. getMtlPlayerTable(function (table) {
  300. $(".mdlPlayers .mdl-content").prepend(table);
  301. $(".mdlPlayerTable-loading").remove();
  302. $(".mdlPlayers .mdl-content").show();
  303. });
  304. getMtlGamesTable(10, function (table) {
  305. $(".mdlGames").prepend(table);
  306. $(".mdlGamesTable-loading").remove();
  307. $("#DashboardLadderTabs-6 .mdlGames table").show();
  308. });
  309. }
  310.  
  311. function getMtlGamesTable(numOfGames, cb) {
  312. var content = $("<div>");
  313. content.prepend('<h4 class="mb-0 py-3"><a href="https://warlight-mtl.com/">Multi-day ladder</a>: Recent Games</h4>');
  314. var table = $("<table>").attr("cellpadding", 2).attr("cellspacing", 0).css("width", "100%").addClass("table table-striped mb-0");
  315. table.append(`
  316. <thead>
  317. <tr>
  318. <td>Game</td>
  319. <td>Link</td>
  320. </tr>
  321. </thead>
  322. `);
  323. table.append("<tbody></table>");
  324. var urlParam = "https://warlight-mtl.com/api/v1.0/games/?topk=" + numOfGames;
  325. var url = "https://maak.ch/wl/httpTohttps.php?url=" + encodeURI(urlParam);
  326. $.ajax({
  327. type: 'GET',
  328. url: url,
  329. dataType: 'jsonp',
  330. crossDomain: true
  331. }).done(function (response) {
  332. var data = JSON.parse(response.data);
  333. var games = data.games;
  334. $.each(games, function (key, game) {
  335. var p1 = game.players[0];
  336. var p2 = game.players[1];
  337. var winner = game.winner_id;
  338. var rowData = "<td>" + getPlayerGameString(p1, p2, winner) + "</td>";
  339. if (game.is_game_deleted) {
  340. rowData += "<td>DELETED</td>"
  341. } else {
  342. rowData += "<td><a href='https://www.warlight.net/MultiPlayer?GameID=" + game.game_id + "'>" + game.game_id + "</a></td>"
  343. }
  344. table.append("<tr>" + rowData + "</tr>")
  345. });
  346. content.append(table);
  347. if (cb) {
  348. cb(content)
  349. }
  350. })
  351. }
  352.  
  353. function getMtlPlayerTable(cb) {
  354. var content = $("<div>");
  355. content.prepend('<h4 class="mb-0 py-3"><a href="https://warlight-mtl.com/">Multi-day ladder</a>: Rankings</h4>');
  356. var table = $("<table>").attr("cellpadding", 2).attr("cellspacing", 0).css("width", "100%").addClass("table table-striped mb-0");
  357. table.append(`
  358. <thead>
  359. <tr>
  360. <td>Rank</td>
  361. <td>Name</td>
  362. <td>Rating</td>
  363. </tr>
  364. </thead>`);
  365. table.append("<tbody></table>");
  366. var urlParam = "https://warlight-mtl.com/api/v1.0/players/?topk=10";
  367. var url = "https://maak.ch/wl/httpTohttps.php?url=" + encodeURI(urlParam);
  368. $.ajax({
  369. type: 'GET',
  370. url: url,
  371. dataType: 'jsonp',
  372. crossDomain: true
  373. }).done(function (response) {
  374. var data = JSON.parse(response.data);
  375. var players = data.players;
  376. players = players.filter(function (p) {
  377. return p.rank <= 10
  378. }).sort(function (p1, p2) {
  379. return p1.rank - p2.rank
  380. });
  381. $.each(players, function (key, player) {
  382. var rowData = "<td>" + player.rank + "</td>";
  383. var playerLink = getPlayerLink(player);
  384. var clanIcon = getClanIcon(player);
  385. rowData += "<td>" + clanIcon + playerLink + "</td>";
  386. rowData += "<td>" + player.displayed_rating + "</td>";
  387. $(table).find("tbody").append("<tr>" + rowData + "</tr>")
  388. });
  389. if (cb) {
  390. content.append(table);
  391. cb(content)
  392. }
  393. })
  394. }
  395.  
  396. function setupMtlForumTable() {
  397. let title = $("title").text().toLowerCase();
  398. title = title.replace(/[^a-zA-Z]/g, '');
  399. if (title.includes("mtl") || title.includes("multitemplate") || title.includes("mdl") || title.includes("multiday")) {
  400. var mdlContainer = setupBottomForumContainer("mdl");
  401. getMtlPlayerTable(function (table) {
  402. mdlContainer.prepend(table)
  403. });
  404. getMtlGamesTable(10, function (table) {
  405. mdlContainer.append(table);
  406. })
  407. }
  408. }
  409.  
  410. function getPlayerGameString(p1, p2, winnerId) {
  411. var c1 = getClanIcon(p1);
  412. var c2 = getClanIcon(p2);
  413. var p1s = c1 + "<a target='_blank' href='https://warlight-mtl.com/player?playerId=" + p1.player_id + "'> " + p1.player_name + "</a>";
  414. var p2s = c2 + "<a target='_blank' href='https://warlight-mtl.com/player?playerId=" + p2.player_id + "'> " + p2.player_name + "</a>";
  415. if (p1.player_id == winnerId) {
  416. return p1s + " defeated " + p2s
  417. } else {
  418. return p2s + " defeated " + p1s
  419. }
  420. }
  421.  
  422. function getPlayerLink(player) {
  423. return "<a href='https://warlight-mtl.com/player?playerId=" + player.player_id + "'> " + player.player_name + "</a>"
  424. }
  425.  
  426. function getClanIcon(player) {
  427. if (player.clan_id) {
  428. return '<a href="https://warlight-mtl.com/clan?clanId=' + player.clan_id + '" title="' + player.clan + '"><img border="0" style="vertical-align: middle" src="' + player.clan_icon + '"></a>'
  429. } else {
  430. return ""
  431. }
  432. }
  433.  
  434. function getRankText(n) {
  435. var s = ["th", "st", "nd", "rd"];
  436. var v = n % 100;
  437. return n + (s[(v - 20) % 10] || s[v] || s[0]);
  438. }
  439.  
  440. function setupBottomForumContainer(className) {
  441. $("#ReplyDiv").after("<div class='" + className + "'></div>");
  442. addCSS(`
  443. .` + className + ` {
  444. padding: 20px;
  445. display: flex;
  446. justify-content: space-between;
  447. }
  448. .` + className + ` > * {
  449. flex: 0.47;
  450. }
  451. .` + className + ` .scroller {
  452. max-height: 750px;
  453. display: block;
  454. overflow-y: auto;
  455. }
  456. `);
  457. return $("." + className);
  458. }
  459. function setupDatabase() {
  460. log("indexedDB start setup");
  461. window.Database = {
  462. db: null,
  463. Table: {
  464. Bookmarks: "Bookmarks",
  465. Settings: "Settings",
  466. BlacklistedForumThreads: "BlacklistedForumThreads",
  467. TournamentData: "TournamentData",
  468. QuickmatchTemplates: "QuickmatchTemplates"
  469. },
  470. Exports: {
  471. Bookmarks: "Bookmarks",
  472. Settings: "Settings",
  473. BlacklistedForumThreads: "BlacklistedForumThreads"
  474. },
  475. Row: {
  476. BlacklistedForumThreads: {
  477. ThreadId: "threadId",
  478. Date: "date"
  479. },
  480. Bookmarks: {
  481. Order: "order"
  482. },
  483. Settings: {
  484. Name: "name"
  485. },
  486. TournamentData: {
  487. Id: "tournamentId"
  488. },
  489. QuickmatchTemplates: {
  490. Id: "setId"
  491. }
  492. },
  493. init: function (callback) {
  494. log("indexedDB start init");
  495. if (!"indexedDB" in window) {
  496. log("IndexedDB not supported");
  497. return;
  498. }
  499. var openRequest = indexedDB.open("TidyUpYourDashboard_v3", 7);
  500. openRequest.onupgradeneeded = function (e) {
  501. var thisDB = e.target.result;
  502. if (!thisDB.objectStoreNames.contains("Bookmarks")) {
  503. var objectStore = thisDB.createObjectStore("Bookmarks", { autoIncrement: true });
  504. objectStore.createIndex("order", "order", { unique: true });
  505. }
  506. if (!thisDB.objectStoreNames.contains("Settings")) {
  507. var objectStore = thisDB.createObjectStore("Settings", { keyPath: "name" });
  508. objectStore.createIndex("name", "name", { unique: true });
  509. objectStore.createIndex("value", "value", { unique: false });
  510. }
  511. if (!thisDB.objectStoreNames.contains("BlacklistedForumThreads")) {
  512. var objectStore = thisDB.createObjectStore("BlacklistedForumThreads", { autoIncrement: true });
  513. objectStore.createIndex("threadId", "threadId", { unique: true });
  514. objectStore.createIndex("date", "date", { unique: false });
  515. }
  516. if (!thisDB.objectStoreNames.contains("TournamentData")) {
  517. var objectStore = thisDB.createObjectStore("TournamentData", { keyPath: "tournamentId" });
  518. objectStore.createIndex("tournamentId", "tournamentId", { unique: true });
  519. objectStore.createIndex("value", "value", { unique: false });
  520. }
  521. if (!thisDB.objectStoreNames.contains("QuickmatchTemplates")) {
  522. var objectStore = thisDB.createObjectStore("QuickmatchTemplates", {
  523. keyPath: "setId",
  524. autoIncrement: true
  525. });
  526. objectStore.createIndex("setId", "setId", { unique: true });
  527. objectStore.createIndex("value", "value", { unique: false });
  528. }
  529. };
  530.  
  531. openRequest.onsuccess = function (e) {
  532. log("indexedDB init sucessful");
  533. db = e.target.result;
  534. callback()
  535. };
  536. openRequest.onblocked = function (e) {
  537. log("indexedDB blocked");
  538. };
  539.  
  540. openRequest.onerror = function (e) {
  541. log("Error Init IndexedDB");
  542. log(e.target.error)
  543. // alert("Sorry, Tidy Up Your Dashboard is not supported")
  544. // $("<div>Sorry,<br> Tidy Up Your Dashboard is not supported.</div>").dialog();
  545. }
  546. },
  547. update: function (table, value, key, callback) {
  548. var transaction = db.transaction([table], "readwrite");
  549. var store = transaction.objectStore(table);
  550.  
  551.  
  552. //Perform the add
  553. try {
  554. if (key == undefined) {
  555. var request = store.put(value);
  556. } else {
  557. var request = store.put(value, Number(key));
  558. }
  559. request.onerror = function (e) {
  560. log(`Error saving ${JSON.stringify(value)} in ${table}`);
  561. log(JSON.stringify(e));
  562. };
  563.  
  564. request.onsuccess = function (e) {
  565. log(`Saved ${JSON.stringify(value)} in ${table}`);
  566. callback()
  567. }
  568. } catch (e) {
  569. log(`Error saving ${JSON.stringify(value)} in ${table}`);
  570. log(JSON.stringify(e));
  571. }
  572.  
  573.  
  574. },
  575. read: function (table, key, callback) {
  576. var transaction = db.transaction([table], "readonly");
  577. var objectStore = transaction.objectStore(table);
  578.  
  579. var ob = objectStore.get(Number(key));
  580.  
  581. ob.onsuccess = function (e) {
  582. var result = e.target.result;
  583. callback(result)
  584. }
  585. },
  586. readIndex: function (table, row, value, callback) {
  587. var transaction = db.transaction([table], "readonly");
  588. var objectStore = transaction.objectStore(table);
  589.  
  590. var index = objectStore.index(row);
  591.  
  592. //name is some value
  593. var ob = index.get(value);
  594.  
  595. ob.onsuccess = function (e) {
  596. var result = e.target.result;
  597. callback(result)
  598. }
  599. },
  600. readAll: function (table, callback) {
  601. var transaction = db.transaction([table], "readonly");
  602. var objectStore = transaction.objectStore(table);
  603. var items = [];
  604.  
  605. var ob = objectStore.openCursor();
  606.  
  607. ob.onsuccess = function (e) {
  608. var cursor = e.target.result;
  609. if (cursor) {
  610. var item = cursor.value;
  611. item.id = cursor.primaryKey;
  612. items.push(item);
  613. cursor.continue();
  614. } else {
  615. callback(items)
  616. }
  617. }
  618. },
  619. add: function (table, value, callback) {
  620.  
  621. var transaction = db.transaction([table], "readwrite");
  622. var store = transaction.objectStore(table);
  623.  
  624. try {
  625. var request = store.add(value);
  626. request.onerror = function (e) {
  627. log(`Error saving ${JSON.stringify(value)} in ${table}`);
  628. log(JSON.stringify(e));
  629. };
  630.  
  631. request.onsuccess = function (e) {
  632. log(`Saved ${JSON.stringify(value)} in ${table}`);
  633. callback()
  634. }
  635. } catch (e) {
  636. log(`Error saving ${JSON.stringify(value)} in ${table}`);
  637. log(JSON.stringify(e));
  638. }
  639. },
  640. delete: function (table, key, callback) {
  641. var transaction = db.transaction([table], "readwrite");
  642. var store = transaction.objectStore(table);
  643.  
  644.  
  645. //Perform the add
  646. var request = store.delete(key);
  647.  
  648. request.onerror = function (e) {
  649. log("Error deleting in " + table);
  650. log(e.target.error);
  651. //some type of error handler
  652. };
  653.  
  654. request.onsuccess = function (e) {
  655. log("Deleted in " + table);
  656. callback()
  657. }
  658. },
  659. clear: function (table, callback) {
  660. var transaction = db.transaction([table], "readwrite");
  661. var store = transaction.objectStore(table);
  662.  
  663.  
  664. //Perform the add
  665. var request = store.clear();
  666.  
  667. request.onerror = function (e) {
  668. log("Error clearing " + table);
  669. log(e.target.error);
  670. //some type of error handler
  671. };
  672.  
  673. request.onsuccess = function (e) {
  674. log("Cleared " + table);
  675. callback()
  676. }
  677. }
  678.  
  679. }
  680.  
  681. }
  682. var mapData;
  683.  
  684. function setupMapSearch() {
  685. $("#PerPageBox").closest("tr").after('<tr><td></td><td><input id="mapSearchQuery" placeholder="Map Name"><br><button id="mapSearchBtn">Search</button><button style="margin: 4px" id="mapSearchResetBtn">Reset</button></td></tr>');
  686.  
  687. $('#mapSearchQuery').on('keypress', function (event) {
  688. if (event.which === 13) {
  689. searchMaps();
  690. }
  691. });
  692.  
  693. $("#mapSearchBtn").on("click", function () {
  694. searchMaps();
  695. });
  696.  
  697. $("#FilterBox, #SortBox, #PerPageBox").on("change", function () {
  698. $("#mapSearchQuery").val("");
  699. $("#searchResultsTitle").remove()
  700. })
  701.  
  702. }
  703.  
  704. function searchMaps() {
  705. if (mapData == undefined) {
  706. $("<div />").load('Ajax/EnumerateMaps?Filter=' + '__all' + '&Sort=' + 1 + "&PerPage=" + 2147483647 + "&Offset=" + 0, function (data) {
  707. mapData = data;
  708. filterMaps(this);
  709. })
  710. } else {
  711. var maps = $("<div />").html(mapData);
  712. filterMaps(maps);
  713. }
  714. }
  715.  
  716. function filterMaps(selector) {
  717. var query = $("#mapSearchQuery").val();
  718. $.each($(selector).find("div"), function (key, div) {
  719. if ($(div).text().trim().toLowerCase().replace(/(rated.*$)/, "").indexOf(query.toLowerCase()) == -1) {
  720. $(div).remove()
  721. }
  722. });
  723.  
  724. var count = $(selector).find("div").length;
  725. $('#MapsContainer').empty();
  726. $(selector).detach().appendTo('#MapsContainer');
  727. $("#MapsContainer tr:last-of-type").html("Showing maps 1 - " + count + " of " + count);
  728. $("#ReceivePager").html("Showing maps 1 - " + count + " of " + count);
  729. $("#searchResultsTitle").length > 0 ? $("#searchResultsTitle").html("Searchresults for <i>" + query + "</i>") : $("#ReceivePager").after("<h2 id='searchResultsTitle'>Searchresults for <i>" + query + "</i></h2>")
  730.  
  731. }
  732. function setupTournamentTableStyles() {
  733. createSelector("body", "overflow: hidden");
  734. $("#MyTournamentsTable").parent().css({
  735. "display": "block",
  736. "overflow-y": "scroll",
  737. "border-bottom": "1px solid #444444",
  738. "border-top": "1px solid #444444"
  739. });
  740. addCSS(`
  741. html, body {
  742. height: 100%;
  743. overflow: hidden;
  744. margin: 0!important;
  745. }
  746. html {
  747. overflow-y: scroll;
  748. }
  749. `);
  750. setTournamentTableHeight();
  751. }
  752.  
  753. function setTournamentTableHeight() {
  754. $("#MyTournamentsTable").parent().height(window.innerHeight - 125);
  755. }
  756.  
  757. function setupPlayerDataTable() {
  758. var dataTable = $$$("#PlayersContainer > table").DataTable({
  759. "order": [[4, "asc"], [3, "desc"]],
  760. paging: false,
  761. sDom: 't',
  762. columnDefs: [{
  763. targets: [0],
  764. orderData: [0, 3]
  765. }, {
  766. targets: [1],
  767. orderData: [1, 0]
  768. }, {
  769. targets: [2],
  770. orderData: [2, 1, 0],
  771. type: "rank"
  772. }, {
  773. targets: [3],
  774. orderData: [3]
  775. }, {
  776. targets: [4],
  777. orderData: [4]
  778. }, {
  779. targets: [5],
  780. orderData: [5, 1, 0]
  781. }],
  782. "aoColumns": [
  783. {
  784. "orderSequence": ["asc", "desc"]
  785. },
  786. {
  787. "orderSequence": ["asc", "desc"]
  788. },
  789. {
  790. "orderSequence": ["asc", "desc"]
  791. },
  792. {
  793. "orderSequence": ["desc", "asc"]
  794. },
  795. {
  796. "orderSequence": ["desc", "asc"]
  797. },
  798. {
  799. "orderSequence": ["desc", "asc"]
  800. }
  801. ]
  802. });
  803. loadDataTableCSS();
  804. }
  805.  
  806.  
  807. function colorTournamentCreatorInChat() {
  808. var creatorLink = $("#HostLabel a:last").attr("href");
  809. addCSS(`
  810. #ChatContainer a[href='` + creatorLink + `'] {
  811. color: cornflowerblue
  812. }
  813. `)
  814. }
  815.  
  816. function setupTournamentTable() {
  817. if ($("#OpenTournamentTable").length == 0) {
  818. return;
  819. }
  820. if ($("#MyTournamentsTable").length == 0) {
  821. $(".SideColumn").prepend('<table class="dataTable" cellspacing="0" width="100%" id="MyTournamentsTable" style="text-align: left;"><thead><tr><td style="text-align: center" colspan="2">Open Tournament</td></tr></thead><tbody></tbody></table><br>');
  822. $("#MyTournamentsTable tbody").append($(".TournamentRow").detach());
  823. }
  824.  
  825. $("#MyTournamentsTable thead td").attr("colspan", "2");
  826. addCSS(`
  827. #MyTournamentsTable tbody .TournamentRow {
  828. background-color: #131313;
  829. text-align: left;
  830. }
  831. `)
  832. }
  833. function setupBookmarkMenu() {
  834. var $body = $("body");
  835. $body.append(`
  836. <div class="modal modal-500 fade" id="bookmarkMenu" tabindex="-1" role="dialog">
  837. <div class="modal-dialog" role="document">
  838. <div class="modal-content">
  839. <div class="modal-header">
  840. <h5 class="modal-title" id="exampleModalLongTitle">Add Bookmark</h5>
  841. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  842. <span aria-hidden="true">&times;</span>
  843. </button>
  844. </div>
  845. <div class="modal-body">
  846. <div class="d-flex flex-column">
  847. <div style="padding:10px" class="d-flex flex-column">
  848. <label for='bookmarkName'>Name</label>
  849. <input type='text' id='bookmarkName'>
  850. <label for='bookmarkURL'>Url</label>
  851. <input id='bookmarkURL' type='text'>
  852. </div>
  853. <div class="form-check">
  854. <label class="form-check-label">
  855. <input id='bookmarkNewWindow' type='checkbox'>
  856. Open in new Window
  857. </label>
  858. </div>
  859. </div>
  860. </div>
  861. <div class="modal-footer">
  862. <button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button>
  863. <button type="button" class="btn btn-success" data-dismiss="modal" onclick='saveBookmark()'>Save</button>
  864. </div>
  865. </div>
  866. </div>
  867. </div>
  868. `);
  869.  
  870. createSelector(".highlightedBookmark", "background-color:rgb(50, 50, 50);cursor:pointer;");
  871. $body.append("<ul class='context-menu bookmark-context'><li onclick='editBookmark()'>Edit</li><li onclick='moveBookmarkUp()'>Move up</li><li onclick='moveBookmarkDown()'>Move Down</li></ul>");
  872. $body.append("<ul class='context-menu thread-context'><li onclick='hideThread()'>Hide</li></ul>");
  873. bindCustomContextMenu()
  874.  
  875. }
  876.  
  877. function setupBookmarkTable() {
  878. $(".SideColumn").prepend('<table class="dataTable" id="BookmarkTable" style="text-align: left;width:100%;"><thead><tr><td style="text-align: center">Bookmarks<img alt="add" src="' + IMAGES.PLUS + '" width="15" height="15" onclick="showAddBookmark()" style="display:inline-block;float:right; opacity: 0.6; margin-right:15px; cursor: pointer"></td></tr></thead></table><br>');
  879.  
  880. refreshBookmarks();
  881. bindBookmarkTable();
  882. }
  883.  
  884. function refreshBookmarks() {
  885. Database.readAll(Database.Table.Bookmarks, function (bookmarks) {
  886. $("#BookmarkTable tbody").remove();
  887. bookmarks.sort(function (a, b) {
  888. return a.order - b.order
  889. });
  890. var data = "<tbody>";
  891. $.each(bookmarks, function (key, bookmark) {
  892. data += '<tr data-bookmarkId="' + bookmark.id + '" data-order="' + bookmark.order + '"><td><a ' + (bookmark.newWindow ? 'target="_blank"' : "") + ' href="' + bookmark.url + '">' + bookmark.name + '</a>';
  893. data += '<a onclick="deleteBookmark(' + bookmark.id + ')" style="display:inline-block;float:right; opacity: 0.6;cursor: pointer;margin-right:5px">';
  894. data += '<span class="ui-icon ui-icon-trash"></span></a></td></tr>';
  895. });
  896.  
  897. $("#BookmarkTable").append(data + '</tbody>');
  898. wljs_WaitDialogJS.Stop();
  899.  
  900. $(".loader").fadeOut("fast", function () {
  901. var $loader = $(".loader");
  902. if ($loader) {
  903. $loader.remove();
  904. window.timeUserscriptReady = new Date().getTime();
  905. log("Time userscript ready " + (timeUserscriptReady - timeUserscriptStart) / 1000)
  906. }
  907. })
  908. })
  909.  
  910.  
  911. }
  912.  
  913. window.bookmarkOrder = undefined;
  914. window.bookmarkId = undefined;
  915. window.showAddBookmark = function () {
  916. $("#bookmarkMenu").modal("show");
  917. window.bookmarkId = undefined;
  918. window.bookmarkOrder = undefined;
  919. $("#bookmarkURL").val("");
  920. $("#bookmarkName").val("");
  921. $("#bookmarkNewWindow").prop("checked", false);
  922. };
  923.  
  924. window.editBookmark = function () {
  925. Database.read(Database.Table.Bookmarks, bookmarkId, function (bookmark) {
  926. $("#bookmarkURL").val(bookmark.url);
  927. $("#bookmarkName").val(bookmark.name);
  928. $("#bookmarkNewWindow").prop("checked", bookmark.newWindow);
  929. $("#bookmarkMenu").modal("show")
  930. })
  931.  
  932. };
  933.  
  934. function moveBookmark(bookmark, previousBookmark1, previousBookmark2) {
  935. bookmark.order = (previousBookmark1.order + previousBookmark2.order) / 2;
  936.  
  937. Database.update(Database.Table.Bookmarks, bookmark, bookmark.id, function () {
  938. $("#bookmarkURL").val('');
  939. $("#bookmarkName").val('');
  940. $("#bookmarkNewWindow").prop('checked', false);
  941. $(".overlay").fadeOut();
  942. refreshBookmarks();
  943. })
  944. }
  945.  
  946. window.moveBookmarkUp = function () {
  947. Database.readAll(Database.Table.Bookmarks, function (bookmarks) {
  948. var bookmark = undefined;
  949. $.each(bookmarks, function (key, bm) {
  950. if (bookmarkId === bm.id) {
  951. bookmark = bm
  952. }
  953. });
  954. bookmarks.sort(function (a, b) {
  955. return a.order - b.order
  956. });
  957. var previousBookmark1 = bookmarks[bookmarks.indexOf(bookmark) - 1];
  958. var previousBookmark2 = bookmarks[bookmarks.indexOf(bookmark) - 2] || { order: 0 };
  959. if (previousBookmark1) {
  960. moveBookmark(bookmark, previousBookmark1, previousBookmark2);
  961. }
  962. })
  963. };
  964.  
  965. window.moveBookmarkDown = function () {
  966. Database.readAll(Database.Table.Bookmarks, function (bookmarks) {
  967. var bookmark = undefined;
  968. $.each(bookmarks, function (key, bm) {
  969. if (bookmarkId === bm.id) {
  970. bookmark = bm
  971. }
  972. });
  973. bookmarks.sort(function (a, b) {
  974. return a.order - b.order
  975. });
  976. var nextBookmark1 = bookmarks[bookmarks.indexOf(bookmark) + 1];
  977. var nextBookmark2 = bookmarks[bookmarks.indexOf(bookmark) + 2] || { order: 100000 };
  978. if (nextBookmark1) {
  979. moveBookmark(bookmark, nextBookmark1, nextBookmark2);
  980. }
  981. })
  982. };
  983.  
  984.  
  985. window.deleteBookmark = function (id) {
  986. Database.delete(Database.Table.Bookmarks, id, function () {
  987. refreshBookmarks();
  988. })
  989. };
  990.  
  991. window.saveBookmark = function () {
  992. $("#bookmarkMenu").hide();
  993. var $bookmarkURL = $("#bookmarkURL");
  994. var url = $bookmarkURL.val().trim();
  995. url = (url.lastIndexOf('http', 0) !== 0) && (url.lastIndexOf('javascript', 0) !== 0) ? "http://" + url : url;
  996.  
  997. var $bookmarkName = $("#bookmarkName");
  998. var name = $bookmarkName.val().trim();
  999. var $bookmarkNewWindow = $("#bookmarkNewWindow");
  1000. var newWindow = $bookmarkNewWindow.prop("checked");
  1001.  
  1002. if (bookmarkId === undefined) {
  1003. Database.readAll(Database.Table.Bookmarks, function (bookmarks) {
  1004. bookmarks.sort(function (a, b) {
  1005. return a.order - b.order
  1006. });
  1007. var bookmark = {
  1008. name: name,
  1009. url: url,
  1010. newWindow: newWindow,
  1011. order: (bookmarks.length > 0) ? bookmarks[bookmarks.length - 1].order + 1 : 1
  1012. };
  1013. Database.add(Database.Table.Bookmarks, bookmark, function () {
  1014. showBookmarkTable();
  1015. refreshBookmarks();
  1016. })
  1017. })
  1018. } else {
  1019. var bookmark = {
  1020. name: name,
  1021. url: url,
  1022. newWindow: newWindow,
  1023. order: bookmarkOrder
  1024. };
  1025. Database.update(Database.Table.Bookmarks, bookmark, bookmarkId, function () {
  1026. showBookmarkTable();
  1027. refreshBookmarks();
  1028. })
  1029. }
  1030.  
  1031. $bookmarkURL.val('');
  1032. $bookmarkName.val('');
  1033. $bookmarkNewWindow.prop('checked', false);
  1034. $(".overlay").fadeOut();
  1035. };
  1036.  
  1037. function showBookmarkTable() {
  1038. var $bookmarkTable = $("#BookmarkTable");
  1039. $bookmarkTable.show();
  1040. if ($bookmarkTable.next().is('br')) {
  1041. $bookmarkTable.next().show();
  1042. }
  1043. }
  1044.  
  1045. window.bookmarkForumThread = function () {
  1046. var title = $("title").text().replace(' - Warzone - Better than Hasbro\'s RISK® game - Play Online Free', '');
  1047. var url = window.location.href;
  1048.  
  1049. showAddBookmark();
  1050. $("#bookmarkURL").val(url);
  1051. $("#bookmarkName").val(title);
  1052. };
  1053. window.bookmarkTournament = function () {
  1054. var title = $("#TournamentName").text().replace("Tournament: ", "").trim();
  1055. var url = window.location.href;
  1056.  
  1057. showAddBookmark();
  1058. $("#bookmarkURL").val(url);
  1059. $("#bookmarkName").val(title);
  1060. };
  1061.  
  1062. window.bookmarkLevel = function () {
  1063. var title = $("h1").text();
  1064. var url = window.location.href;
  1065.  
  1066. showAddBookmark();
  1067. $("#bookmarkURL").val(url);
  1068. $("#bookmarkName").val(title);
  1069. };
  1070.  
  1071. function addDefaultBookmark() {
  1072. var bookmark = {
  1073. name: "Muli's userscript (Tidy up Your Dashboard)",
  1074. url: "https://www.warlight.net/Forum/106092-tidy-up-dashboard-2",
  1075. newWindow: false,
  1076. order: 0
  1077. };
  1078. Database.add(Database.Table.Bookmarks, bookmark, function () {
  1079. showBookmarkTable();
  1080. refreshBookmarks();
  1081. })
  1082. }
  1083.  
  1084. function bindBookmarkTable() {
  1085. $("#BookmarkTable").bind("contextmenu", function (event) {
  1086. $(".highlightedBookmark").removeClass("highlightedBookmark");
  1087. var row = $(event.target).closest("tr");
  1088.  
  1089.  
  1090. window.bookmarkId = Number(row.attr("data-bookmarkid"));
  1091. window.bookmarkOrder = Number(row.attr("data-order"));
  1092.  
  1093. if (bookmarkId && bookmarkOrder) {
  1094. event.preventDefault();
  1095. row.addClass("highlightedBookmark");
  1096. // Show contextmenu
  1097. $(".bookmark-context").finish().toggle(100).css({
  1098. top: event.pageY + "px",
  1099. left: event.pageX + "px"
  1100. });
  1101. }
  1102.  
  1103. });
  1104. }
  1105.  
  1106. function setupLevelBookmark() {
  1107. $("h1").after(`
  1108. <a style="cursor:pointer;color: #5a9da5;" onclick="bookmarkLevel()">Bookmark</a><br>
  1109. `)
  1110. }
  1111. function setupLadderClotOverview() {
  1112. console.log("setupLadderClotOverview");
  1113. $("h1").text($("h1").text() + " & Community Events");
  1114. loadClots(function (clotInfo) {
  1115. console.log("clotInfo");
  1116. console.log(clotInfo);
  1117. if (!clotInfo) {
  1118. return
  1119. }
  1120. var ladders = clotInfo['leagues'];
  1121. var md = "";
  1122. var rt = "";
  1123. var leagues = "";
  1124. var counter = 0;
  1125. $.each(ladders, function (key, val) {
  1126. if (val.type == "realtime") {
  1127. rt += "<li><big><a target='_blank' href=" + val.url + ">" + val.name + "</a> using Real-Time boot times</big></li><br><br>";
  1128. counter++
  1129. } else if (val.type == "multiday") {
  1130. md += "<li><big><a target='_blank' href = " + val.url + ">" + val.name + "</a> using Multi-Day boot times</big></li><br><br>";
  1131. counter++
  1132. } else {
  1133. leagues += `<li><big><a target='_blank' href="${val.url}">${val.name}</a> ${getPlayerString(val.players)}</big></li><br><br>`;
  1134. counter++
  1135. }
  1136.  
  1137. });
  1138. var $mainSite = $("#AutoContainer > div");
  1139. $mainSite.append("Warzone currently has " + toWords(counter) + " Community Events:<br><br>");
  1140.  
  1141. $mainSite.append("<ul id='clotInfo'></ul>");
  1142. let $clotInfo = $("#clotInfo");
  1143. $clotInfo.append(rt);
  1144. $clotInfo.append(md);
  1145. $clotInfo.append(leagues)
  1146. });
  1147. }
  1148.  
  1149. function getPlayerString(players) {
  1150. if (players) {
  1151. return `<span class='clotPlayers'>${players} players participating</span>`
  1152. }
  1153. return ""
  1154. }
  1155.  
  1156. function loadClots(cb) {
  1157. log("loading clots");
  1158. $.ajax({
  1159. type: 'GET',
  1160. url: 'https://raw.githubusercontent.com/psenough/wl_clot/master/hub/list.jsonp',
  1161. dataType: 'text',
  1162. crossDomain: true
  1163. }).done(function (response) {
  1164. try {
  1165. var response = eval(response);
  1166. console.log(response.data);
  1167. var json = response.data;
  1168. var clotInfo = JSON.stringify(json);
  1169. sessionStorage.setItem('clots', clotInfo);
  1170. if (cb) {
  1171. cb(json)
  1172. }
  1173.  
  1174. var datetime = json.datetime;
  1175. log("clot update " + datetime)
  1176.  
  1177. } catch (e) {
  1178. log("Error parsing CLOTs");
  1179. log(e)
  1180. }
  1181. }).fail(function (e) {
  1182. log("Error loading CLOTs");
  1183. log(e);
  1184. });
  1185. }
  1186.  
  1187. function toWords(number) {
  1188.  
  1189. var NS = [
  1190. { value: 1000000000000000000000, str: "sextillion" },
  1191. { value: 1000000000000000000, str: "quintillion" },
  1192. { value: 1000000000000000, str: "quadrillion" },
  1193. { value: 1000000000000, str: "trillion" },
  1194. { value: 1000000000, str: "billion" },
  1195. { value: 1000000, str: "million" },
  1196. { value: 1000, str: "thousand" },
  1197. { value: 100, str: "hundred" },
  1198. { value: 90, str: "ninety" },
  1199. { value: 80, str: "eighty" },
  1200. { value: 70, str: "seventy" },
  1201. { value: 60, str: "sixty" },
  1202. { value: 50, str: "fifty" },
  1203. { value: 40, str: "forty" },
  1204. { value: 30, str: "thirty" },
  1205. { value: 20, str: "twenty" },
  1206. { value: 19, str: "nineteen" },
  1207. { value: 18, str: "eighteen" },
  1208. { value: 17, str: "seventeen" },
  1209. { value: 16, str: "sixteen" },
  1210. { value: 15, str: "fifteen" },
  1211. { value: 14, str: "fourteen" },
  1212. { value: 13, str: "thirteen" },
  1213. { value: 12, str: "twelve" },
  1214. { value: 11, str: "eleven" },
  1215. { value: 10, str: "ten" },
  1216. { value: 9, str: "nine" },
  1217. { value: 8, str: "eight" },
  1218. { value: 7, str: "seven" },
  1219. { value: 6, str: "six" },
  1220. { value: 5, str: "five" },
  1221. { value: 4, str: "four" },
  1222. { value: 3, str: "three" },
  1223. { value: 2, str: "two" },
  1224. { value: 1, str: "one" }
  1225. ];
  1226.  
  1227. var result = '';
  1228. for (var n of NS) {
  1229. if (number >= n.value) {
  1230. if (number <= 20) {
  1231. result += n.str;
  1232. number -= n.value;
  1233. if (number > 0) result += ' ';
  1234. } else {
  1235. var t = Math.floor(number / n.value);
  1236. var d = number % n.value;
  1237. if (d > 0) {
  1238. return intToEnglish(t) + ' ' + n.str + ' ' + intToEnglish(d);
  1239. } else {
  1240. return intToEnglish(t) + ' ' + n.str;
  1241. }
  1242.  
  1243. }
  1244. }
  1245. }
  1246. return result;
  1247. }
  1248. window.userscriptSettings = [
  1249. {
  1250. id: 'scrollGames',
  1251. text: 'Fixed Window with Scrollable Games',
  1252. selected: true,
  1253. title: 'Dashboard',
  1254. addBreak: false,
  1255. help: 'This option displays My-, Open-, Coin-Games in a scrollable box, which removes a lot of unesessary scrolling. You can find tabs to switch between the different type of games. '
  1256. },
  1257. {
  1258. id: 'hideMyGamesIcons',
  1259. text: 'Hide Icons in "My Games"',
  1260. selected: false,
  1261. title: '',
  1262. addBreak: false,
  1263. help: 'This option hides game icons for My Games on the dashboard'
  1264. },
  1265. {
  1266. id: 'autoRefreshOnFocus',
  1267. text: 'Automatically Refresh Games on Tab-Focus',
  1268. selected: true,
  1269. title: '',
  1270. addBreak: false,
  1271. help: 'This option automatically refreshes your games after switching back to WarLight from a different tab / program. This only applies if WarLight was idle for 30 or more seconds.'
  1272. },
  1273. {
  1274. id: 'highlightTournaments',
  1275. text: 'Highlight Tournament Invites',
  1276. selected: false,
  1277. title: '',
  1278. addBreak: false
  1279. },
  1280. {
  1281. id: 'hideCoinsGlobally',
  1282. text: 'Hide Coins Globally',
  1283. selected: false,
  1284. title: '',
  1285. addBreak: false,
  1286. help: 'This option removes everything from Warlight related to Coins'
  1287. },
  1288. {
  1289. id: 'useDefaultBootLabel',
  1290. text: 'Use the Default Boot Time Label',
  1291. selected: false,
  1292. title: 'Advanced',
  1293. addBreak: false
  1294. },
  1295. {
  1296. id: 'showPrivateNotesOnProfile',
  1297. text: 'Show Private Notes on Profile',
  1298. selected: true,
  1299. title: '',
  1300. addBreak: false,
  1301. help: 'This option will show you your private notes which you made on a player directly on their profile page. You can find them on the left side under the profile picture.'
  1302. },
  1303. {
  1304. id: 'hideOffTopic',
  1305. text: 'Automatically Hide Off-Topic Threads',
  1306. selected: false,
  1307. title: '',
  1308. addBreak: false,
  1309. help: 'This option automatically hides all off-topic threads everytime you visit the All Forum Posts page'
  1310. }, {
  1311. id: 'hideWarzoneIdle',
  1312. text: 'Automatically Hide Warzone Idle Threads',
  1313. selected: false,
  1314. title: '',
  1315. addBreak: false,
  1316. help: 'This option automatically hides all warzone idle threads everytime you visit the All Forum Posts page'
  1317. },
  1318. {
  1319. id: 'disableHideThreadOnDashboard',
  1320. text: 'Disable Right-Click on the Forum Table',
  1321. selected: false,
  1322. title: '',
  1323. addBreak: false,
  1324. help: 'This option will allow you to right-click forum thread on the dashboard and use the default browser options.'
  1325. }
  1326. ];
  1327.  
  1328. /**
  1329. * Creates the Userscript-Menu
  1330. */
  1331. function setupUserscriptMenu() {
  1332. addCSS(`
  1333. /* The switch - the box around the slider */
  1334. .switch {
  1335. position: relative;
  1336. width: 50px;
  1337. height: 24px;
  1338. margin-right: 30px;
  1339. float: right;
  1340. }
  1341.  
  1342. /* Hide default HTML checkbox */
  1343. .switch input {display:none;}
  1344.  
  1345. /* The slider */
  1346. .slider {
  1347. position: absolute;
  1348. cursor: pointer;
  1349. top: 0;
  1350. left: 0;
  1351. right: 0;
  1352. bottom: 0;
  1353. background-color: #ccc;
  1354. -webkit-transition: .4s;
  1355. transition: .4s;
  1356. }
  1357.  
  1358. .slider:before {
  1359. position: absolute;
  1360. content: "";
  1361. height: 20px;
  1362. width: 20px;
  1363. left: 2px;
  1364. bottom: 2px;
  1365. background-color: white;
  1366. -webkit-transition: .4s;
  1367. transition: .4s;
  1368. }
  1369.  
  1370. input:checked + .slider {
  1371. background-color: #0E5C83;
  1372. }
  1373.  
  1374. input:focus + .slider {
  1375. box-shadow: 0 0 1px crimson;
  1376. }
  1377.  
  1378. input:checked + .slider:before {
  1379. -webkit-transform: translateX(26px);
  1380. -ms-transform: translateX(26px);
  1381. transform: translateX(26px);
  1382. }
  1383.  
  1384. /* Rounded sliders */
  1385. .slider.round {
  1386. border-radius: 34px;
  1387. }
  1388.  
  1389. .slider.round:before {
  1390. border-radius: 50%;
  1391. }
  1392. .settingsListItem {
  1393. padding-top: 25px;
  1394. font-size: 15px;
  1395. }
  1396. `);
  1397. var inputs = '';
  1398. $.each(userscriptSettings, function (key, setting) {
  1399. if (setting.title != '') {
  1400. inputs += `<div class="title">${setting.title}</div>`;
  1401. }
  1402. var help = setting.help != undefined ? `<img tabindex="0" class="help-icon" src="${IMAGES.QUESTION}" data-content="${getSettingInfo(setting.id)}" data-toggle="popover">` : '';
  1403. inputs += '<div class="settingsListItem">' + setting.text + help + '<label class="switch"><input id="' + setting.id + '" type="checkbox"><div class="slider round"></div></label></div>';
  1404. if (setting.addBreak) {
  1405. inputs += '<hr>';
  1406. }
  1407. });
  1408. $("body").append(`
  1409. <div class="modal modal-750 fade" id="userscriptMenu" tabindex="-1" role="dialog">
  1410. <div class="modal-dialog" role="document">
  1411. <div class="modal-content">
  1412. <div class="modal-header">
  1413. <h5 class="modal-title" id="exampleModalLongTitle">Muli's Userscript ${GM_info.script.version}</h5>
  1414. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  1415. <span aria-hidden="true">&times;</span>
  1416. </button>
  1417. </div>
  1418. <div class="modal-body">
  1419. ${inputs}
  1420. </div>
  1421. <div class="modal-footer">
  1422. <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
  1423. <button type="button" class="btn btn-primary close-userscript" data-dismiss="modal">Close & Refresh</button>
  1424. </div>
  1425. </div>
  1426. </div>
  1427. </div>
  1428. `);
  1429. $("body").append('<ul class="custom-menu"><div class="content"></div></ul>');
  1430. if (typeof $().popover === 'function') {
  1431. $("[data-toggle=popover]").popover({
  1432. trigger: 'focus'
  1433. });
  1434. }
  1435. $("#userscriptMenu").on("change", function () {
  1436. console.log("storing settings");
  1437. storeSettingsVariables();
  1438. });
  1439. $("#AccountDropDown").next(".dropdown-menu").append('<div class="dropdown-divider"></div><a class="dropdown-item " href="#" data-toggle="modal" data-target="#userscriptMenu">Muli\'s Userscript</a>');
  1440. $(".close-userscript").on("click", function () {
  1441. $(".userscript-show").fadeOut();
  1442. $(".overlay").fadeOut();
  1443. location.reload();
  1444. });
  1445. $(".close-popup-img").on("click", function () {
  1446. $(".userscript-show").fadeOut();
  1447. $(".overlay").fadeOut();
  1448. $("embed#main").css('opacity', '1');
  1449. });
  1450. $("#hideCoinsGlobally").parent().parent().after('<button class="btn btn-primary" data-toggle="modal" data-target="#dashboardTableSortMenu" style="margin-top:15px;">Sort Right Column Tables</button><br>');
  1451. createSelector("#sortTables", "margin-top: 5px");
  1452. addCSS(`
  1453. .userscriptSettingsButtons {
  1454. display: flex;
  1455. justify-content: space-between;
  1456. margin-top: 25px;
  1457. }
  1458. `);
  1459. $("#userscriptMenu .modal-body").append("<div class='userscriptSettingsButtons'></div>");
  1460. //Export settings button
  1461. $(".userscriptSettingsButtons").append('<button data-target="#userscriptExportSettings" data-toggle="modal" id="exportSettings" class="btn btn-primary">Export Settings</button>');
  1462. //Import settings button
  1463. $(".userscriptSettingsButtons").append('<button data-toggle="modal" data-target="#userscriptImportSettings" class="btn btn-primary">Import Settings</button>');
  1464. //Reset hidden threads button
  1465. $(".userscriptSettingsButtons").append('<button id="resetHiddenThreads" class="btn btn-primary">Reset Hidden Threads</button>');
  1466. $("body").append(`
  1467. <div class="modal fade" id="userscriptExportSettings" tabindex="-1" role="dialog">
  1468. <div class="modal-dialog" role="document">
  1469. <div class="modal-content">
  1470. <div class="modal-header">
  1471. <h5 class="modal-title" id="exampleModalLongTitle">Export Settings</h5>
  1472. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  1473. <span aria-hidden="true">&times;</span>
  1474. </button>
  1475. </div>
  1476. <div class="modal-body">
  1477. Copy or download this text and save it somewhere on your computer!
  1478. <textarea id='exportSettingsBox'></textarea>
  1479. <a id='downloadExportSettingsFile' href='' download='tuyd_settings.txt'>Download Text-File</a>
  1480. </div>
  1481. <div class="modal-footer">
  1482. <button type="button" data-dismiss="modal" class="btn btn-primary close-userscript">Close</button>
  1483. </div>
  1484. </div>
  1485. </div>
  1486. </div>
  1487. `);
  1488. $("body").append(`
  1489. <div class="modal fade" id="userscriptImportSettings" tabindex="-1" role="dialog">
  1490. <div class="modal-dialog" role="document">
  1491. <div class="modal-content">
  1492. <div class="modal-header">
  1493. <h5 class="modal-title" id="exampleModalLongTitle">Import Settings</h5>
  1494. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  1495. <span aria-hidden="true">&times;</span>
  1496. </button>
  1497. </div>
  1498. <div class="modal-body">
  1499. <textarea id='importSettingsBox' placeholder='Copy settings here'></textarea><button id='importSettings' class="btn btn-primary">Import Settings</button>
  1500. </div>
  1501. <div class="modal-footer">
  1502. <button type="button" data-dismiss="modal" class="btn btn-primary close-userscript">Close</button>
  1503. </div>
  1504. </div>
  1505. </div>
  1506. </div>
  1507. `);
  1508. createSelector("#exportSettingsBox, #importSettingsBox", "width:100%; height: 300px");
  1509. $("#exportSettings").on("click", function () {
  1510. exportSettings();
  1511. });
  1512. $("#importSettings").on("click", function () {
  1513. importSettings();
  1514. });
  1515. $("#resetHiddenThreads").on("click", function () {
  1516. window.undoIgnore();
  1517. });
  1518. getSortTables(function (tables) {
  1519. var tableCode = '';
  1520. $.each(tables, function (key, table) {
  1521. tableCode += '<div class="sortableLadder ' + (table.hidden ? 'tableSortHidden' : '') + '" data-name="' + table.name + '" data-tableId="' + table.id + '">' + table.name + '<div class="tableSortNavigation"><span class="tableSortUp">▲</span><span class="tableSortDown">▼</span><span class="tableSortHideShow"><img src="' + IMAGES.EYE + '"></span></div></div>'
  1522. });
  1523. createSelector(".sortableLadder", "border: 1px gray solid;margin: 5px;padding: 5px;background-color:rgb(25, 25, 25);");
  1524. createSelector(".tableSortNavigation", "display: inline-block;float: right;margin-top: -2px;");
  1525. createSelector(".tableSortNavigation span", "padding: 3px 10px; cursor: pointer");
  1526. createSelector(".tableSortNavigation span:hover", "color: #C0D0FF");
  1527. createSelector(".sortTableHighlight", "background-color: rgb(60, 60, 60)");
  1528. createSelector(".tableSortHideShow img", "height: 10px");
  1529. createSelector(".tableSortHidden", "opacity: 0.2;");
  1530. $("body").append(`
  1531. <div class="modal modal-500 fade" id="dashboardTableSortMenu" tabindex="-1" role="dialog">
  1532. <div class="modal-dialog" role="document">
  1533. <div class="modal-content">
  1534. <div class="modal-header">
  1535. <h5 class="modal-title" id="exampleModalLongTitle">Sort dashboard tables</h5>
  1536. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  1537. <span aria-hidden="true">&times;</span>
  1538. </button>
  1539. </div>
  1540. <div class="modal-body">
  1541. ${tableCode}
  1542. </div>
  1543. <div class="modal-footer">
  1544. <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
  1545. <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="window.saveTableSort()">Save</button>
  1546. </div>
  1547. </div>
  1548. </div>
  1549. </div>
  1550. `);
  1551. $(".close-popup-img").unbind();
  1552. $(".close-popup-img").on("click", function () {
  1553. $(".popup").fadeOut();
  1554. $(".overlay").fadeOut();
  1555. });
  1556. $(".tableSortUp").on("click", function () {
  1557. $(".sortTableHighlight").removeClass("sortTableHighlight");
  1558. var table = $(this).closest(".sortableLadder");
  1559. table.addClass("sortTableHighlight");
  1560. var prev = table.prev();
  1561. table = table.detach();
  1562. prev.before(table)
  1563. });
  1564. $(".tableSortDown").on("click", function () {
  1565. $(".sortTableHighlight").removeClass("sortTableHighlight");
  1566. var table = $(this).closest(".sortableLadder");
  1567. table.addClass("sortTableHighlight");
  1568. var next = table.next();
  1569. table = table.detach();
  1570. next.after(table)
  1571. });
  1572. $(".tableSortHideShow").on("click", function () {
  1573. $(".sortTableHighlight").removeClass("sortTableHighlight");
  1574. var table = $(this).closest(".sortableLadder");
  1575. table.addClass("sortTableHighlight");
  1576. table.toggleClass("tableSortHidden")
  1577. });
  1578. checkUserscriptMenuButtons();
  1579. })
  1580. }
  1581.  
  1582. function importSettings() {
  1583. var deferredCount = 0;
  1584. var resolvedCount = 0;
  1585. var clearPromises = [];
  1586. $.each(Database.Table, function (key, table) {
  1587. clearPromises[deferredCount++] = $.Deferred();
  1588. Database.clear(table, function () {
  1589. clearPromises[resolvedCount++].resolve();
  1590. })
  1591. });
  1592. wljs_WaitDialogJS.Start(null, "Importing Settings...")
  1593.  
  1594. $('.modal').modal("hide");
  1595. var settings = $("#importSettingsBox").val().trim();
  1596. $.when.apply($, clearPromises).done(function () {
  1597. var deferredCount = 0;
  1598. var resolvedCount = 0;
  1599. var promises = [];
  1600. try {
  1601. settings = JSON.parse(atob(settings));
  1602. $.each(settings, function (key, data) {
  1603. var table = data.table;
  1604. var content = data.data;
  1605. $.each(content, function (key, value) {
  1606. promises[deferredCount++] = $.Deferred();
  1607. Database.add(table, value, function () {
  1608. promises[resolvedCount++].resolve();
  1609. })
  1610. })
  1611. });
  1612. $.when.apply($, promises).done(function () {
  1613. window.location.reload();
  1614. })
  1615. } catch (e) {
  1616. log(e);
  1617. wljs_WaitDialogJS.Stop();
  1618. CreateModal("mulisuserscript", "Error", "There was an error importing the settings.");
  1619. $(".overlay").fadeOut();
  1620. }
  1621. });
  1622. }
  1623.  
  1624. function exportSettings() {
  1625. var settings = [];
  1626. var deferredCount = 0;
  1627. var resolvedCount = 0;
  1628. var promises = [];
  1629. $.each(Database.Exports, function (key, table) {
  1630. promises[deferredCount++] = $.Deferred();
  1631. Database.readAll(table, function (data) {
  1632. settings.push({
  1633. table: table,
  1634. data: data
  1635. });
  1636. promises[resolvedCount++].resolve();
  1637. })
  1638. });
  1639. $.when.apply($, promises).done(function () {
  1640. var settingsString = btoa(JSON.stringify(settings));
  1641. $("#exportSettingsBox").html(settingsString);
  1642. showPopup(".exportSettings-show");
  1643. $("#downloadExportSettingsFile").click(function () {
  1644. this.href = "data:text/plain;charset=UTF-8," + settingsString;
  1645. });
  1646. });
  1647. }
  1648.  
  1649. function showPopup(selector) {
  1650. if ($(selector).length > 0) {
  1651. $(".popup").fadeOut();
  1652. $(selector).fadeIn();
  1653. $(".overlay").fadeIn();
  1654. makePopupVisible();
  1655. }
  1656. }
  1657.  
  1658. function makePopupVisible() {
  1659. let popup = $(".popup600:visible");
  1660. if (popup.offset() && popup.offset().top + popup.height() + 150 > $(window).height() || (popup.offset() && popup.offset().top < 100)) {
  1661. popup.css("margin-top", $(window).height() - 250 - popup.height());
  1662. $(".popup600:visible .head").css("margin-top", $(window).height() - 250 - popup.height() + 2)
  1663. }
  1664. }
  1665.  
  1666. function getSortTables(callback) {
  1667. var defaultTables = [
  1668. {
  1669. id: "#BookmarkTable",
  1670. name: "Bookmarks",
  1671. hidden: false,
  1672. order: 0
  1673. },
  1674. {
  1675. id: "#MyTournamentsTable",
  1676. name: "Open Tournaments",
  1677. hidden: false,
  1678. order: 2
  1679. },
  1680. {
  1681. id: "#MapOfTheWeekTable",
  1682. name: "Map of the Week",
  1683. hidden: false,
  1684. order: 4
  1685. },
  1686. {
  1687. id: "#ForumTable",
  1688. name: "Forum Posts",
  1689. hidden: false,
  1690. order: 5
  1691. },
  1692. {
  1693. id: "#ClanForumTable",
  1694. name: "Clan Forum Posts",
  1695. hidden: false,
  1696. order: 6
  1697. },
  1698. {
  1699. id: "#BlogTable",
  1700. name: "Recent Blog Posts",
  1701. hidden: false,
  1702. order: 7
  1703. },
  1704. {
  1705. id: "#LeaderboardTable",
  1706. name: "Coin Leaderboard",
  1707. hidden: false,
  1708. order: 8
  1709. }
  1710. ];
  1711. if ($("#ShopTable").length > 0) {
  1712. defaultTables.push({
  1713. id: "#ShopTable",
  1714. name: "WarLight Shop",
  1715. hidden: false,
  1716. order: -1
  1717. })
  1718. }
  1719. if ($(".dataTable thead td:contains('Quickmatch')").length > 0) {
  1720. defaultTables.push({
  1721. id: ".dataTable thead:contains('Quickmatch')",
  1722. name: "Quickmatch",
  1723. hidden: false,
  1724. order: 1
  1725. })
  1726. }
  1727. Database.readIndex(Database.Table.Settings, Database.Row.Settings.Name, "tableSort", function (tableData) {
  1728. if (tableData && tableData.value.length > 3) {
  1729. var tables = tableData.value;
  1730. if ($("#ShopTable").length > 0 && !arrayHasObjWithId(tables, "#ShopTable")) {
  1731. tables.push({
  1732. id: "#ShopTable",
  1733. name: "WarLight Shop",
  1734. hidden: false,
  1735. order: -1
  1736. })
  1737. }
  1738. if ($(".dataTable thead td:contains('Quickmatch')").length > 0 && !arrayHasObjWithId(tables, ".dataTable thead:contains('Quickmatch')")) {
  1739. tables.push({
  1740. id: ".dataTable thead:contains('Quickmatch')",
  1741. name: "Quickmatch",
  1742. hidden: false,
  1743. order: 1
  1744. })
  1745. }
  1746. callback($(tables).sort(compareTable));
  1747. } else {
  1748. callback($(defaultTables).sort(compareTable))
  1749. }
  1750. })
  1751. }
  1752.  
  1753. function arrayHasObjWithId(arr, id) {
  1754. var found = false;
  1755. $.each(arr, function (key, val) {
  1756. if (val.id == id) {
  1757. found = true;
  1758. }
  1759. });
  1760. return found;
  1761. }
  1762.  
  1763. window.saveTableSort = function () {
  1764. var tables = [];
  1765. $.each($("#dashboardTableSortMenu div.sortableLadder"), function (key, table) {
  1766. var order = key;
  1767. var id = $(table).attr('data-tableId');
  1768. var hidden = $(table).hasClass("tableSortHidden");
  1769. var name = $(table).attr('data-name');
  1770. tables.push({
  1771. id: id,
  1772. name: name,
  1773. hidden: hidden,
  1774. order: order
  1775. })
  1776. });
  1777. var tableSort = {
  1778. name: "tableSort",
  1779. value: tables
  1780. };
  1781. Database.update(Database.Table.Settings, tableSort, undefined, function () {
  1782. $("#sortTablePopup").fadeOut();
  1783. $(".overlay").fadeOut();
  1784. refreshOpenGames();
  1785. })
  1786. };
  1787.  
  1788. function compareTable(a, b) {
  1789. if (a.order < b.order) return -1;
  1790. if (a.order > b.order) return 1;
  1791. return 0;
  1792. }
  1793.  
  1794. window.getSettingInfo = function (id) {
  1795. var help = "";
  1796. $.each(userscriptSettings, function (key, setting) {
  1797. if (setting.id == id) {
  1798. help = setting.help;
  1799. }
  1800. });
  1801. return help;
  1802. };
  1803.  
  1804. function checkUserscriptMenuButtons() {
  1805. $.each(userscriptSettings, function (key, set) {
  1806. Database.readIndex(Database.Table.Settings, Database.Row.Settings.Name, set.id, function (setting) {
  1807. if (setting) {
  1808. $("#" + setting.name).prop("checked", setting.value);
  1809. } else {
  1810. $("#" + set.id).prop("checked", set.selected);
  1811. }
  1812. })
  1813. });
  1814. }
  1815.  
  1816. /**
  1817. * Stores User-Settings to local Storage
  1818. */
  1819. function storeSettingsVariables() {
  1820. $.each(userscriptSettings, function (key, set) {
  1821. var isEnabled = $("#" + set.id).prop("checked");
  1822. var setting = {
  1823. name: set.id,
  1824. value: isEnabled
  1825. };
  1826. Database.update(Database.Table.Settings, setting, undefined, function () {
  1827. })
  1828. });
  1829. }
  1830.  
  1831. function setupSettingsDatabase() {
  1832. wljs_WaitDialogJS.Start(null, "Setting up Muli's Userscript...")
  1833.  
  1834. var promises = [];
  1835. $.each(userscriptSettings, function (key, set) {
  1836. promises[key] = $.Deferred();
  1837. var setting = {
  1838. name: set.id,
  1839. value: set.selected
  1840. };
  1841. Database.update(Database.Table.Settings, setting, undefined, function () {
  1842. promises[key].resolve();
  1843. })
  1844. });
  1845. $.when.apply($, promises).done(function () {
  1846. sessionStorage.setItem("showUserscriptMenu", true);
  1847. window.setTimeout(window.location.reload(), 2000)
  1848. })
  1849. }
  1850.  
  1851. function ifSettingIsEnabled(setting, positive, negative, cb) {
  1852. Database.readIndex(Database.Table.Settings, Database.Row.Settings.Name, setting, function (setting) {
  1853. if (setting && setting.value) {
  1854. positive();
  1855. if (typeof cb == "function") {
  1856. cb();
  1857. }
  1858. } else {
  1859. if (typeof negative == 'function') {
  1860. negative();
  1861. }
  1862. if (typeof cb == 'function') {
  1863. cb();
  1864. }
  1865. }
  1866. })
  1867. }
  1868. function pageIsMultiplayer() {
  1869. return location.href.match(/.*warzone[.]com\/MultiPlayer.*/i);
  1870. }
  1871.  
  1872. function pageIsPointsPage() {
  1873. return location.href.match(/.*warzone[.]com\/Points.*/i);
  1874. }
  1875.  
  1876. function pageIsDashboard() {
  1877. return location.href.match(/.*warzone[.]com\/MultiPlayer\/(?:#|\?|$).*$/i);
  1878. }
  1879.  
  1880. function pageIsProfile() {
  1881. return location.href.match(/.*warzone[.]com\/profile\?p=[0-9]+/i);
  1882. }
  1883.  
  1884. function pageIsLevelOverview() {
  1885. return location.href.match(/.*warzone[.]com\/SinglePlayer\/Level\?ID=[0-9]+$/i);
  1886. }
  1887.  
  1888. function pageIsLevelPlayLog() {
  1889. return location.href.match(/.*warzone[.]com\/SinglePlayer\/PlayLog\?ID=[0-9]+$/i);
  1890. }
  1891.  
  1892. function pageIsMapsPage() {
  1893. return location.href.match(/.*warzone[.]com\/maps/i);
  1894. }
  1895.  
  1896. function pageIsNewThread() {
  1897. return location.href.match(/.*warzone[.]com\/Forum\/NewThread.*/i);
  1898. }
  1899.  
  1900. function pageIsForumThread() {
  1901. return location.href.match(/.*warzone[.]com\/Forum\/[0-9]+.*/i);
  1902. }
  1903.  
  1904. function pageIsForumOverview() {
  1905. return location.href.match(/.*warzone[.]com\/Forum\/Forum.*/i);
  1906. }
  1907.  
  1908. function pageIsThread() {
  1909. return location.href.match(/.*warzone[.]com\/(Forum|Discussion|Clans\/CreateThread).*/i);
  1910. }
  1911.  
  1912. function pageIsSubForum() {
  1913. return location.href.match(/.*warzone[.]com\/Forum\/[A-Z]+.*/i);
  1914. }
  1915.  
  1916. function pageIsLadderOverview() {
  1917. return location.href.match(/.*warzone[.]com\/Ladders/);
  1918. }
  1919.  
  1920. function pageIsLogin() {
  1921. return location.href.match(/.*warzone[.]com\/LogIn.*/);
  1922. }
  1923.  
  1924. function pageIsClanForumThread() {
  1925. return location.href.match(/.*warzone[.]com\/Discussion\/\?ID=[0-9]+.*/);
  1926. }
  1927.  
  1928. function pageIsTournament() {
  1929. return location.href.match(/.*warzone[.]com\/MultiPlayer\/Tournament\?ID=[0-9]+/i);
  1930. }
  1931.  
  1932. function pageIsTournamentOverview() {
  1933. return location.href.match(/.*warzone[.]com\/MultiPlayer\/Tournaments\/$/i);
  1934. }
  1935.  
  1936. function pageIsGame() {
  1937. return location.href.match(/.*warzone[.]com\/MultiPlayer\?GameID=[0-9]+/i);
  1938. }
  1939.  
  1940. function pageIsExamineMap() {
  1941. return location.href.match(/.*warzone[.]com\/SinglePlayer\?PreviewMap.*/i);
  1942. }
  1943.  
  1944. function pageIsDesignMap() {
  1945. return location.href.match(/.*warzone[.]com\/MultiPlayer\?DesignMaps.*/i);
  1946. }
  1947.  
  1948. function pageIsCommonGames() {
  1949. return location.href.match(/.*warzone[.]com\/CommonGames\?p=[0-9]+$/i);
  1950. }
  1951.  
  1952. function pageIsQuickmatch() {
  1953. return location.href.match(/.*warzone[.]com\/multiplayer\?quickmatch/i);
  1954. }
  1955.  
  1956. function pageIsCommunityLevels() {
  1957. return location.href.match(/.*warzone[.]com\/SinglePlayer\/CommunityLevels/i);
  1958. }
  1959.  
  1960. function pageIsCommunity() {
  1961. return location.href.match(/.*warzone[.]com\/Community/i);
  1962. }
  1963.  
  1964. function pageIsMapOfTheWeek() {
  1965. return location.href.match(/.*warzone[.]com\/MapOfTheWeek.*/i);
  1966. }
  1967.  
  1968. function pageIsBlacklistPage() {
  1969. return location.href.match(/.*warzone[.]com\/ManageBlackList.*/i);
  1970. }
  1971.  
  1972. function pageIsMapPage() {
  1973. return location.href.match(/.*warzone[.]com\/Map.*/i);
  1974. }
  1975.  
  1976. function mapIsPublic() {
  1977. return $("a:contains('Start a')").length > 0;
  1978. }
  1979. function addCSS(css) {
  1980. var head = document.head || document.getElementsByTagName('head')[0];
  1981. var style = document.createElement('style');
  1982. style.type = 'text/css';
  1983. if (head) {
  1984. if (style.styleSheet) {
  1985. style.styleSheet.cssText = css;
  1986. } else {
  1987. style.appendChild(document.createTextNode(css));
  1988. }
  1989. head.appendChild(style);
  1990. } else {
  1991. $$$(document).ready(function () {
  1992. addCSS(css)
  1993. })
  1994. }
  1995. }
  1996.  
  1997. /**
  1998. * Create a CSS selector
  1999. * @param name The name of the object, which the rules are applied to
  2000. * @param rules The CSS rules
  2001. */
  2002. function createSelector(name, rules) {
  2003. var head = document.head || document.getElementsByTagName('head')[0];
  2004. var style = document.createElement('style');
  2005. style.type = 'text/css';
  2006. if (head) {
  2007. head.appendChild(style);
  2008. if (!(style.sheet || {}).insertRule) {
  2009. (style.styleSheet || style.sheet).addRule(name, rules);
  2010. } else {
  2011. style.sheet.insertRule(name + "{" + rules + "}", 0);
  2012. }
  2013. } else {
  2014. $$$(document).ready(function () {
  2015. createSelector(name, rules)
  2016. })
  2017. }
  2018. }
  2019.  
  2020. function setGlobalStyles() {
  2021. /** Warzone **/
  2022. addCSS(`
  2023. body > .container-fluid {
  2024. font-size: 15px;
  2025. }
  2026. .modal-1000 .modal-dialog {
  2027. max-width: 1000px;
  2028. }
  2029. .modal-750 .modal-dialog {
  2030. max-width: 750px;
  2031. }
  2032. .modal-500 .modal-dialog {
  2033. max-width: 500px;
  2034. }
  2035. .modal-dialog {
  2036. border: 1px gray solid;
  2037. }
  2038. .modal-header {
  2039. background-image: radial-gradient(circle at center,#88888855,transparent),url(https://warzonecdn.com/Images/Warzone/MainNavBacking2.jpg);
  2040. background-repeat: no-repeat,repeat;
  2041. background-size: 100% 100%,194px 194px;
  2042. }
  2043. .modal-content {
  2044. background-image: linear-gradient(-10deg,#33333322 0%,transparent 70%),url(https://warzonecdn.com/Images/Warzone/Background2.jpg);
  2045. background-repeat: no-repeat,repeat;
  2046. background-size: 100% 100%,10px 15px;
  2047. color: grey;
  2048. }
  2049. .modal-content a {
  2050. color: #5a9da5;
  2051. }
  2052. .modal-content .title {
  2053. border-bottom: 1px solid #928f59;
  2054. margin-top: 25px;
  2055. }
  2056. .p-4 table {
  2057. width: 100%;
  2058. }
  2059. .GameRow p {
  2060. margin: 0 !important;
  2061. }
  2062. h2, h3 {
  2063. font-size: 25px;
  2064. }
  2065. img[src*='/Images/X.png'] {
  2066. width: 100%;
  2067. height: 100%;
  2068. }
  2069. `);
  2070.  
  2071. /** Warlight **/
  2072.  
  2073. $("tr:contains('WarLight Shop')").closest(".dataTable").attr("id", "ShopTable");
  2074. createSelector('.help-icon', 'display:inline-block;position:absolute; margin-left:10px;margin-top: 2px;cursor:pointer; height: 15px; width: 15px;');
  2075. var winHeight = $(window).height();
  2076. createSelector(".popup", "position: fixed;;left: 50%;background: #171717;top: 100px;z-index: 9999; color:white;padding:60px 30px 30px 30px;border: 2px solid gray;border-radius:8px;max-height:" + (winHeight - 200) + "px;overflow-y:auto");
  2077. createSelector(".close-popup-img", "float:right;margin:5px;cursor:pointer;margin-right: 20px");
  2078. addCSS(`.popup .title {
  2079. color: crimson;
  2080. font-size: 15px;
  2081. margin-top: 10px;
  2082. display: inline-block;
  2083. width: 95%;
  2084. padding-bottom: 3px;
  2085. border-bottom: 1px solid crimson;
  2086. }`);
  2087. createSelector(".popup input[type='checkbox']", "width: 20px;height: 20px;margin-left:30px;margin: 5px;");
  2088. createSelector(".overlay", "position: absolute;background: white;top: 0;left: 0;right: 0;bottom: 0;z-index: 98;opacity: 0.5;width: 100%;height: 100%;position: fixed;");
  2089. createSelector(".popup .head", "position: fixed;height: 40px;background: #330000;width: 660px;left: 0;right: 0;top: 100px;color: white;font-size: 15px;text-align: center;line-height: 40px;border-top-left-radius:8px;border-top-right-radius:8px;margin:auto;z-index:10000;");
  2090. createSelector(".userscript-show", "display:none");
  2091. createSelector(".newSetting", "color: gold;font-weight: bold;");
  2092. createSelector(".userscript-menu img", "height: 18px;display: inline-block;position: relative;margin-bottom: -5px;margin-right: 7px;");
  2093. createSelector(".custom-menu", "display: none;z-index: 98;position: absolute;overflow: hidden;border: 1px solid #CCC;white-space: nowrap;font-family: sans-serif;background: #FFF;color: #333;border-radius:5px;padding: 10px;z-index:100000000; cursor:pointer");
  2094. createSelector(".custom-menu .content", "width: 300px;white-space: pre-wrap;");
  2095. createSelector('.popup input[type="text"]', 'display: inline-block;background: none;border-top: none;border-left: none;border-right: none;color: green;font-size: 15px;border-bottom: 1px white dashed;font-family: Verdana;padding: 0 5px 0 5px;text-align: center;margin-right: 5px');
  2096. createSelector(".popup840", "width: 840px;margin-left: -452px");
  2097. createSelector(".popup600", "width: 600px;margin-left: -332px");
  2098. createSelector(".popup840 .head", "width: 900px");
  2099. createSelector(".popup600 .head", "width: 660px");
  2100. createSelector(".context-menu", "display: none;z-index: 100;position: absolute;overflow: hidden;border: 1px solid #CCC;white-space: nowrap;font-family: sans-serif;background: #FFF;color: #333;border-radius: 5px;padding: 0;");
  2101. createSelector(".context-menu li", "padding: 8px 12px;cursor: pointer;list-style-type: none;");
  2102. createSelector(".context-menu li:hover", "background-color: #DEF;");
  2103. createSelector("#MyGamesTable select", "margin: 0 10px 0 5px; width: 125px");
  2104. createSelector("#MyGamesFilter", "float:right");
  2105. createSelector("#MyGamesTable thead tr", "text-align: right");
  2106. $("body").on("click", function (e) {
  2107. if ($(".custom-menu").is(':visible')) {
  2108. $(".custom-menu").hide(100);
  2109. }
  2110. });
  2111. }
  2112.  
  2113. function loadDataTableCSS() {
  2114. var styles = document.createElement("style");
  2115. styles.type = "text/css";
  2116. styles.innerHTML = getDataTableCSS();
  2117. document.body.appendChild(styles);
  2118. }
  2119.  
  2120. function getDataTableCSS() {
  2121. return `table.dataTable thead td,table.dataTable thead th{padding:6px 18px 6px 6px}table.dataTable tfoot td,table.dataTable tfoot th{padding:10px 18px 6px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc{cursor:pointer}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url(https://cdn.datatables.net/1.10.10/images/sort_both.png)}table.dataTable thead .sorting_asc{background-image:url(https://cdn.datatables.net/1.10.10/images/sort_asc.png)}table.dataTable thead .sorting_desc{background-image:url(https://cdn.datatables.net/1.10.10/images/sort_desc.png)}table.dataTable thead .sorting_asc_disabled{background-image:url(https://cdn.datatables.net/1.10.10/images/sort_asc_disabled.png)}table.dataTable thead .sorting_desc_disabled{background-image:url(https://cdn.datatables.net/1.10.10/images/sort_desc_disabled.png)}.dataTables_wrapper{position:relative;clear:both;zoom:1}#PlayersContainer td{white-space:nowrap}
  2122.  
  2123. .dataTables_filter {
  2124. float: right;
  2125. }
  2126.  
  2127. .dataTables_filter label {
  2128. display: inline!important;
  2129. }
  2130.  
  2131. .dataTables_filter input {
  2132. padding: 3px;
  2133. border-radius: 5px;
  2134. margin: 5px;
  2135. }
  2136.  
  2137. .dataTables_info {
  2138. clear: both;
  2139. padding-top: 10px;
  2140. }
  2141.  
  2142. .pagination {
  2143. display: inline-block;
  2144. float: right;
  2145.  
  2146. }
  2147. #foundClansTable_wrapper .row {
  2148. width: 100%;
  2149. }
  2150. .paginate_button {
  2151. display: inline;
  2152. padding: 5px;
  2153. }.paginate_button.active {
  2154. text-decoration: underline;
  2155. }`
  2156. }
  2157. function domRefresh() {
  2158. $("body").hide(0).show(0);
  2159. $(window).trigger('resize')
  2160. }
  2161.  
  2162. function htmlEscape(str) {
  2163. return String(str)
  2164. .replace(/&/g, '&amp;')
  2165. .replace(/"/g, '&quot;')
  2166. .replace(/'/g, '&#39;')
  2167. .replace(/</g, '&lt;')
  2168. .replace(/>/g, '&gt;');
  2169. }
  2170.  
  2171. function hideTable(selector) {
  2172. $(selector).closest("table").remove()
  2173. }
  2174.  
  2175. function browserIsFirefox() {
  2176. return navigator.userAgent.toLowerCase().indexOf('firefox') > -1
  2177. }
  2178.  
  2179. function setupImages() {
  2180. window.IMAGES = {
  2181. EYE: 'https://i.imgur.com/kekYrsO.png',
  2182. CROSS: 'https://i.imgur.com/RItbpDS.png',
  2183. QUESTION: 'https://i.imgur.com/TUyoZOP.png',
  2184. PLUS: 'https://i.imgur.com/lT6SvSY.png',
  2185. SAVE: 'https://i.imgur.com/Ze4h3NQ.png',
  2186. FILTER: 'https://i.imgur.com/Q5Jq3EX.png?1',
  2187. BOOKMARK: 'https://i.imgur.com/c6IxAql.png'
  2188.  
  2189. }
  2190. }
  2191.  
  2192. Array.prototype.unique = function () {
  2193. var n = {}, r = [];
  2194. for (var i = 0; i < this.length; i++) {
  2195. if (!n[this[i]]) {
  2196. n[this[i]] = true;
  2197. r.push(this[i]);
  2198. }
  2199. }
  2200. return r;
  2201. };
  2202.  
  2203. function createUJSMenu(title, className, cb) {
  2204. $(".navbar-nav .nav-item:first").before(`
  2205. <li class="nav-item dropdown ${className}">
  2206. <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">${title}</a>
  2207. <div class="dropdown-menu p-0 br-3 ${className}-dropdown"></div>
  2208. </li>`);
  2209. if (typeof cb == "function") {
  2210. $("." + className).on("click", cb)
  2211. }
  2212. }
  2213.  
  2214. function createUJSSubMenu(parentClass, name, className) {
  2215. $("." + parentClass).append(`
  2216. <li class="dropdown-submenu" id="` + className + `">
  2217. <a class="dropdown-toggle dropdown-item" data-toggle="dropdown" href="#" aria-expanded="true">` + name + `</a>
  2218. <ul class="dropdown-menu ` + className + `" aria-labelledby="navbarDropdownMenuLink"></ul>
  2219.  
  2220. </li>
  2221. `)
  2222. }
  2223.  
  2224. function createUJSSubMenuEntry(parent, name, cb) {
  2225. var entry = $('<li><a class="dropdown-item" href="#">' + name + '</a></li>');
  2226. $("." + parent).append(entry);
  2227. if (typeof cb == "function") {
  2228. $(entry).on("click", cb)
  2229. }
  2230. return entry;
  2231. }
  2232. function setupWLError() {
  2233. window.wlerror = window.onerror;
  2234. window.onerror = windowError;
  2235. window.timeDomContentReady = new Date().getTime();
  2236. log("Time DOM content ready " + (timeDomContentReady - timeUserscriptStart) / 1000);
  2237. log("DOM content ready");
  2238.  
  2239. window.WLError = function (a, b) {
  2240. logError(a);
  2241. null == a && (a = "");
  2242. console.log("WLError: " + a + ", silent=" + b);
  2243. -1 != a.indexOf("NotAuth") ? location.reload() : -1 != a.indexOf("WarLight Server returned CouldNotConnect") ? CNCDialog() : -1 == a.indexOf("TopLine is not defined") && -1 == a.indexOf("_TPIHelper") && -1 == a.indexOf("Syntax error, unrecognized expression: a[href^=http://]:not([href*=") && -1 == a.indexOf("y2_cc2242") && -1 == a.indexOf("Error calling method on NPObject") && (-1 != a.indexOf("WARLIGHTERROR48348927984712893471394") ? a = "ServerError" : -1 !=
  2244. a.indexOf("WARLIGHTHEAVYLOAD48348927984712893471394") && (a = "HeavyLoad"), ReportError(a), b || PopErrorDialog(a))
  2245. }
  2246. }
  2247. function hideCoinsGlobally() {
  2248. $("#LeaderboardTable").prev().remove();
  2249. $("#LeaderboardTable").css({
  2250. opacity: 0,
  2251. cursor: 'default'
  2252. });
  2253. $("#LeaderboardTable a").css('display', 'none');
  2254. $("body").find("a[href='/Coins/']").css('display', 'none');
  2255.  
  2256. $("a[href='/Win-Money']").css('display', 'none');
  2257. $("#OpenTournamentsTable").css('display', 'none');
  2258. }
  2259.  
  2260. const totalPointsPerLevel = {
  2261. 1: 0,
  2262. 2: 7000,
  2263. 3: 14300,
  2264. 4: 22100,
  2265. 5: 30200,
  2266. 6: 38800,
  2267. 7: 47900,
  2268. 8: 57400,
  2269. 9: 67400,
  2270. 10: 77900,
  2271. 11: 89000,
  2272. 12: 100700,
  2273. 13: 113000,
  2274. 14: 125900,
  2275. 15: 139500,
  2276. 16: 153800,
  2277. 17: 168900,
  2278. 18: 184800,
  2279. 19: 201500,
  2280. 20: 219100,
  2281. 21: 237600,
  2282. 22: 257000,
  2283. 23: 277500,
  2284. 24: 299100,
  2285. 25: 321800,
  2286. 26: 345700,
  2287. 27: 370800,
  2288. 28: 397200,
  2289. 29: 425100,
  2290. 30: 454400,
  2291. 31: 485200,
  2292. 32: 517700,
  2293. 33: 551900,
  2294. 34: 587800,
  2295. 35: 625700,
  2296. 36: 665500,
  2297. 37: 707400,
  2298. 38: 751600,
  2299. 39: 798000,
  2300. 40: 846900,
  2301. 41: 898300,
  2302. 42: 952400,
  2303. 43: 1009400,
  2304. 44: 1069400,
  2305. 45: 1132500,
  2306. 46: 1198900,
  2307. 47: 1268800,
  2308. 48: 1342400,
  2309. 49: 1419800,
  2310. 50: 1501300,
  2311. 51: 1587100,
  2312. 52: 1677400,
  2313. 53: 1772400,
  2314. 54: 1872400,
  2315. 55: 2092800,
  2316. 56: 2571800,
  2317. 57: 3402400,
  2318. 58: 4710900,
  2319. 59: 6668800,
  2320. 60: 9509500,
  2321. 61: 13549800,
  2322. 62: 19220700,
  2323. 63: 27107600,
  2324. 64: 38006500,
  2325. 65: 52998900,
  2326. 66: 73554900,
  2327. 67: 101672700,
  2328. 68: 140067600,
  2329. 69: 192430500,
  2330. 70: 263777500
  2331. };
  2332.  
  2333. function displayTotalPointsEarned() {
  2334. let totalPoints = totalPointsPerLevel[WlPlayer.Level] + WlPlayer.PointsThisLevel;
  2335. $(".container.px-4").append(`<br><span>In total, you've earned <b>${totalPoints.toLocaleString("en")}</b> points.</span>`)
  2336. }
  2337. function hideExtraBlanks() {
  2338. var content = $(".container .my-2:first-of-type div.p-3");
  2339. var replacement = '<br><br>';
  2340. content.html(content.html().replace(/(<br\s*\/?>){3,}/gi, replacement))
  2341. }
  2342.  
  2343. function foldProfileStats() {
  2344. addCSS(`
  2345. h3.expander {
  2346. cursor: pointer;
  2347. `);
  2348. $.each($("big").parent().contents(), function (key, val) {
  2349. if (val.nodeType == 3) {
  2350. $(val).replaceWith(`<span>${val.data}</span>`)
  2351. }
  2352. });
  2353. $.each($(".container .my-2:first-of-type div.p-3 h3"), function (key, val) {
  2354. $(val).addClass("expander");
  2355. $(val).nextUntil("h3").wrapAll("<div class='exp'></div>")
  2356. });
  2357. $('h3.expander').click(function (e) {
  2358. $(this).next().slideToggle();
  2359. });
  2360. }
  2361.  
  2362. function showGlobalWinRate() {
  2363. var regex = /\((\d*)[^\d]*(\d*).*\)/g;
  2364. let $h3 = $("h3:contains('Ranked Games')");
  2365. var text = $h3.next().find("span:contains('ranked games')").text();
  2366. var matches = regex.exec(text);
  2367. if (matches !== null) {
  2368. $h3.next().find("span:contains('ranked games')").append(", " + Math.round(matches[1] / matches[2] * 100) + "%")
  2369. }
  2370. }
  2371.  
  2372. function loadCommunityLevelRecords() {
  2373. var playerId = location.href.match(/p=(\d+)/)[1];
  2374. $.ajax({
  2375. type: 'GET',
  2376. url: `https://maak.ch/wl/v2/api.php?player=${playerId}`,
  2377. dataType: 'jsonp',
  2378. crossDomain: true
  2379. }).done(function (response) {
  2380. if (response.data) {
  2381. var records = response.data;
  2382. $("h3:contains('Single-player stats')").after(`<font class="text-muted">Community Levels:</font> <span><a href="http://communitylevels.online" target="_blank"> ${records} record${records != 1 ? "s" : ""}</a></span>`);
  2383. }
  2384. });
  2385. }
  2386.  
  2387.  
  2388. function loadPrivateNotes() {
  2389. log("Loading private notes");
  2390. $("#FeedbackMsg").after('<div class="profileBox" id="privateNotes"><h3>Private Notes</h3><p style="width: 285px;overflow:hidden" class="content">Loading Privates Notes..</p></div>');
  2391. var url = "https://www.warzone.com" + $(".container a[href*='Discussion/Notes']").attr("href")
  2392. var page = $('<div />').load(url, function () {
  2393. var notes = page.find('#PostForDisplay_0').html().trim();
  2394. if (notes) {
  2395. $('#privateNotes .content').html(notes);
  2396. } else {
  2397. $('#privateNotes .content').html('You don\'t have any Private Notes.');
  2398. }
  2399.  
  2400. });
  2401. }
  2402.  
  2403. function displayTrophies() {
  2404. var trophies = {
  2405. 5286630035: ["Get on the immediate roadmap"]
  2406. };
  2407.  
  2408. Object.keys(trophies).forEach(playerId => {
  2409. if (window.location.href.indexOf(playerId) != -1) {
  2410. trophies[playerId].forEach(text => {
  2411. $("h3:contains('Achievements ')").next().find("tbody").prepend('<tr title="Trophy awarded by Muli"> <td> <img style="vertical-align: middle" src="https://warzonecdn.com/Images/TrophyImage.png" width="21" height="20"> </td> <td>Trophy: ' + text + '</td> </tr>')
  2412. })
  2413. }
  2414. });
  2415. }
  2416. function databaseReady() {
  2417. log("Running main");
  2418. if (pageIsForumOverview()) {
  2419. ifSettingIsEnabled("hideOffTopic", function () {
  2420. hideOffTopicThreads()
  2421. });
  2422. ifSettingIsEnabled("hideWarzoneIdle", function () {
  2423. hideWarzoneIdleThreads()
  2424. });
  2425. formatHiddenThreads();
  2426. }
  2427. if (pageIsCommunityLevels()) {
  2428. setupCommunityLevels()
  2429. }
  2430.  
  2431. if (pageIsForumOverview() || pageIsSubForum()) {
  2432. setupSpammersBeGone();
  2433. addCSS(`
  2434. #MainSiteContent > table table tr td:nth-of-type(4), #MainSiteContent > table table tr td:nth-of-type(5) {
  2435. max-width: 200px;
  2436. overflow: hidden;
  2437. text-overflow: ellipsis;
  2438. }
  2439. `)
  2440. }
  2441. if (pageIsProfile() && $("#BlockListLink").length > 0) {
  2442. ifSettingIsEnabled('showPrivateNotesOnProfile', function () {
  2443. loadPrivateNotes();
  2444. })
  2445. }
  2446. if (pageIsCommunity()) {
  2447. hideIgnoredForumThreadsFromCommnuityList();
  2448. }
  2449. if (pageIsBlacklistPage()) {
  2450. $("#MainSiteContent ul").before(`<span id="numBlacklisted">You have <b>${$("#MainSiteContent ul li:visible").length}</b> players on your blacklist.</span>`);
  2451. window.setInterval(function () {
  2452. $("#numBlacklisted").replaceWith(`<span id="numBlacklisted">You have <b>${$("#MainSiteContent ul li:visible").length}</b> players on your blacklist.</span>`)
  2453. }, 500)
  2454. }
  2455. if (pageIsPointsPage()) {
  2456. displayTotalPointsEarned();
  2457. }
  2458. if (pageIsDashboard()) {
  2459. setupVacationAlert();
  2460.  
  2461. hideBlacklistedThreads();
  2462. setupBasicDashboardStyles();
  2463. Database.readIndex(Database.Table.Settings, Database.Row.Settings.Name, "customFilter", function (f) {
  2464. var filter = (f && f.value) ? f.value : 4;
  2465. refreshMyGames();
  2466. });
  2467. ifSettingIsEnabled('hideCoinsGlobally', function () {
  2468. hideCoinsGlobally()
  2469. });
  2470. ifSettingIsEnabled('useDefaultBootLabel', function () {
  2471. createSelector(".BootTimeLabel", "z-index:50;");
  2472. }, function () {
  2473. createSelector(".BootTimeLabel", "color:white !important;font-weight:normal!important;font-style:italic;font-size:13px!important;z-index:50;");
  2474. });
  2475. ifSettingIsEnabled("highlightTournaments", function () {
  2476. createSelector("#MyTournamentsTable tbody", "background:#4C4C33;");
  2477. });
  2478. ifSettingIsEnabled("hideMyGamesIcons", function () {
  2479. createSelector("#MyGamesTable td div > img, #MyGamesTable td div a > img", "display:none;");
  2480. });
  2481. ifSettingIsEnabled("scrollGames", function () {
  2482. setupFixedWindowWithScrollableGames();
  2483. }, function () {
  2484. createSelector("body", "overflow: auto");
  2485. createSelector("#MainSiteContent > table", "width: 100%;max-width: 1400px;");
  2486. addCSS(`
  2487. @media (max-width: 1050px) {
  2488. #MyGamesTable > thead > tr * {
  2489. font-size: 14px;
  2490. }
  2491. #MyGamesTable > thead > tr > td > div:nth-of-type(1) {
  2492. margin-top: 5px!important;
  2493. display: block;
  2494. float: left;
  2495. padding-right: 5px;
  2496. }
  2497. }
  2498.  
  2499. @media (max-width: 750px) {
  2500. #MyGamesTable > thead > tr > td > div:nth-of-type(1) {
  2501. display:none;
  2502. }
  2503. }`)
  2504. }, function () {
  2505. setupRightColumn(true);
  2506. refreshOpenGames();
  2507. });
  2508. $("label#MultiDayRadio").on("click", function () {
  2509. registerGameTabClick()
  2510. });
  2511. $("label#RealTimeRadio").on("click", function () {
  2512. registerGameTabClick()
  2513. });
  2514. $("label#BothRadio").on("click", function () {
  2515. registerGameTabClick()
  2516. });
  2517. $(window).resize(function () {
  2518. ifSettingIsEnabled("scrollGames", function () {
  2519. refreshSingleColumnSize();
  2520. }, undefined, function () {
  2521. makePopupVisible()
  2522. })
  2523. });
  2524. window.setTimeout(setupRefreshFunction, 0);
  2525. } else {
  2526. ifSettingIsEnabled('hideCoinsGlobally', function () {
  2527. hideCoinsGlobally();
  2528. })
  2529. }
  2530. }
  2531. function DOM_ContentReady() {
  2532. $(".order-xl-2").addClass("SideColumn");
  2533.  
  2534. log("DOM content ready");
  2535. if ($(".navbar").length > 0) {
  2536. log("Unity is not full screen")
  2537. } else {
  2538. log("Unity is full screen");
  2539. return;
  2540. }
  2541.  
  2542. $.extend($$$.fn.dataTableExt.oSort, {
  2543. "rank-pre": function (a) {
  2544. return a.match(/([0-9]*)/)[1] || 9999;
  2545. },
  2546. "rank-asc": function (a, b) {
  2547. return a < b;
  2548. },
  2549. "rank-desc": function (a, b) {
  2550. return a > b;
  2551. }
  2552. });
  2553.  
  2554. $.extend($$$.fn.dataTableExt.oSort, {
  2555. "numeric-comma-pre": function (a) {
  2556. return Number(a.replace(/,/g, ""))
  2557. },
  2558. "numeric-comma-asc": function (a, b) {
  2559. return a < b;
  2560. },
  2561. "numeric-comma-desc": function (a, b) {
  2562. return a > b;
  2563. }
  2564. });
  2565.  
  2566. setupWLError();
  2567. createSelector('body > footer', 'display:none');
  2568.  
  2569. $.fn.outerHTML = function (s) {
  2570. return s ? this.before(s).remove() : jQuery("<p>").append(this.eq(0).clone()).html();
  2571. };
  2572.  
  2573. if (pageIsNewThread()) {
  2574. $("[onclick='undoIgnore()']").closest("th").remove();
  2575. $(".checkbox").closest("td").remove()
  2576. }
  2577.  
  2578. if (document.getElementById("MyGamesFilter") != null) {
  2579. document.getElementById("MyGamesFilter").onchange = null
  2580. }
  2581. $("#MyGamesFilter").on("change", function () {
  2582. var customFilter = $(this).val();
  2583. Database.update(Database.Table.Settings, {
  2584. name: "customFilter",
  2585. value: customFilter
  2586. }, undefined, function () {
  2587. refreshMyGames();
  2588. })
  2589. });
  2590.  
  2591. if (pageIsDashboard()) {
  2592. $("body").append("<div class='loader' style=' background: black;position: fixed;left: 0;right: 0;top: 0;bottom: 0;z-index: 100;'></div>");
  2593. $(".container-fluid").show();
  2594. window.lastRefresh;
  2595. window.lastClick = new Date();
  2596. }
  2597.  
  2598. if (pageIsThread()) {
  2599. setupTextarea()
  2600. }
  2601.  
  2602. if (pageIsMapPage() && mapIsPublic()) {
  2603. var id = location.href.match(/[^\d]*([\d]*)/)[1];
  2604. $("#MainSiteContent ul").append(`<li><a href="https://www.warzone.com/RateMap?ID=${id}" target="_blank">Rate Map</a></li>`)
  2605. }
  2606.  
  2607. if (pageIsCommunity()) {
  2608. setupMtlLadderTable();
  2609. }
  2610.  
  2611. if (pageIsForumThread() || pageIsClanForumThread()) {
  2612. $("[href='#Reply']").after(" | <a href='#' style='cursor:pointer' onclick='bookmarkForumThread()'>Bookmark</a>");
  2613. $("#PostReply").after(" | <a href='#' style='cursor:pointer' onclick='bookmarkForumThread()'>Bookmark</a>");
  2614. $(".region a[href*='2211733141']:contains('Muli')").closest("td").find("a:contains('Report')").before("<a href='https://www.warzone.com/Forum/106092-mulis-userscript-tidy-up-dashboard'><font color='#FFAE51' size='1'>Script Creator</font></a><br>");
  2615. setupMtlForumTable();
  2616. $(".region a[href='/Profile?u=Muli_1']:contains('Muli')").closest("td").find("br:nth-of-type(5)").remove();
  2617. $("[id^=PostForDisplay]").find("img").css("max-width", "100%");
  2618. parseForumSPLevels();
  2619. $('img[src*="https://s3.amazonaws.com/data.warlight.net/Data/Players"]').prev().remove();
  2620. $(".region td:first-of-type").css("padding-top", "10px");
  2621. addCSS(`
  2622. img[src*='Images/Thumbs'] {
  2623. height: 25px;
  2624. width: 25px;
  2625. }
  2626. `)
  2627. }
  2628. loadPlayerData();
  2629. if (pageIsTournament()) {
  2630. window.setTimeout(function () {
  2631. setupPlayerDataTable();
  2632. }, 50);
  2633. $("#HostLabel").after(" | <a style='cursor:pointer' href='#' onclick='bookmarkTournament()'>Bookmark</a>");
  2634. $("#HostLabel").css("display", "inline-block");
  2635. $("#LeftToStartMessage").text(" | " + $("#LeftToStartMessage").text());
  2636. createSelector("#LeftToStartMessage:before", "content: ' | '");
  2637. createSelector("#ChatContainer", "clear:both");
  2638. $("input").on("keypress keyup keydown", function (e) {
  2639. e.stopPropagation()
  2640. });
  2641. addCSS(`
  2642. #ChatContainer div {
  2643. margin-bottom: 10px;
  2644. }
  2645. `);
  2646. colorTournamentCreatorInChat();
  2647.  
  2648. }
  2649.  
  2650. if (pageIsCommonGames()) {
  2651. window.$ = $$$;
  2652. setupCommonGamesDataTable()
  2653. }
  2654.  
  2655. if (pageIsTournamentOverview()) {
  2656. setupTournamentTableStyles();
  2657. $(window).resize(function () {
  2658. setTournamentTableHeight();
  2659. });
  2660. $(window).on("scroll", function () {
  2661. $(window).scrollTop(0)
  2662. })
  2663. }
  2664.  
  2665. if (pageIsLadderOverview()) {
  2666. setupLadderClotOverview();
  2667.  
  2668. }
  2669.  
  2670. if (pageIsMapsPage()) {
  2671. setupMapSearch()
  2672. }
  2673.  
  2674. if (pageIsLevelPlayLog()) {
  2675. setupPlayerAttempDataTable();
  2676. }
  2677.  
  2678. if (pageIsLevelOverview()) {
  2679. setupLevelBookmark();
  2680. }
  2681.  
  2682. if (pageIsProfile()) {
  2683. createSelector(".profileBox", "background-image: url(\'https://d2wcw7vp66n8b3.cloudfront.net/Images/ProfileSpeedBackground.png\'); background-repeat: no-repeat; text-align: left; padding:10px;margin-top: 12px;");
  2684. hideExtraBlanks();
  2685. displayTrophies();
  2686. foldProfileStats();
  2687. showGlobalWinRate();
  2688. setupMtlProfile();
  2689. loadCommunityLevelRecords();
  2690. }
  2691.  
  2692. setGlobalStyles();
  2693. if (pageIsMapOfTheWeek()) {
  2694. addCSS(`
  2695. .dataTable table {
  2696. display: block;
  2697. }
  2698. `)
  2699. }
  2700. Database.init(function () {
  2701. log("database is ready");
  2702. if (pageIsDashboard()) {
  2703. wljs_WaitDialogJS.Start(null, "Tidying Up...")
  2704. }
  2705. window.setTimeout(validateUser, 2000);
  2706. setupUserscriptMenu();
  2707. setupBookmarkMenu();
  2708. checkVersion();
  2709. databaseReady();
  2710. });
  2711.  
  2712. if (pageIsMultiplayer() && $("#UjsContainer").length == 0) {
  2713. // setupDashboardSearch() // remove search as it is broken
  2714. }
  2715. }
  2716.  
  2717. window.undoIgnore = function () {
  2718. // reset blacklisted threads to empty list
  2719. Database.clear(Database.Table.BlacklistedForumThreads, function () {
  2720. if (pageIsForumOverview() || pageIsSubForum()) {
  2721. $("#MainSiteContent > table tbody table:nth-of-type(2) tr .checkbox").prop("checked", false);
  2722. $("#MainSiteContent > table tbody table:nth-of-type(2) tr").show()
  2723. } else if (pageIsDashboard()) {
  2724. $("#ForumTable tr").show()
  2725. } else {
  2726. location.reload;
  2727. }
  2728. })
  2729.  
  2730. };
  2731.  
  2732. function replaceAndFilterForumTable(tableHTML) {
  2733. var table = $.parseHTML(tableHTML);
  2734. var promises = [];
  2735. $.each($(table).find("tr"), function (key, row) {
  2736.  
  2737. if (threadId = $(row).html().match(/href="\/Forum\/([^-]*)/mi)) {
  2738. promises[key] = $.Deferred();
  2739. Database.readIndex(Database.Table.BlacklistedForumThreads, Database.Row.BlacklistedForumThreads.ThreadId, threadId[1], function (thread) {
  2740. if (thread) {
  2741. $(row).hide();
  2742. }
  2743. promises[key].resolve();
  2744. })
  2745. }
  2746. });
  2747. $.when.apply($, promises).done(function () {
  2748. $("#ForumTable").replaceWith($(table).outerHTML());
  2749.  
  2750. ifSettingIsEnabled('disableHideThreadOnDashboard', function () {
  2751.  
  2752. }, function () {
  2753. $("#ForumTable").unbind();
  2754. $("#ForumTable").bind("contextmenu", function (event) {
  2755. $(".highlightedBookmark").removeClass("highlightedBookmark");
  2756.  
  2757. var row = $(event.target).closest("tr");
  2758. row.addClass("highlightedBookmark");
  2759. // Avoid the real one
  2760.  
  2761. if (row.is(":last-child")) {
  2762. return;
  2763. }
  2764. event.preventDefault();
  2765. threadId = row.html().match(/href="\/Forum\/([^-]*)/mi);
  2766. if (threadId) {
  2767. activeThreadId = threadId[1]
  2768. } else {
  2769. return
  2770. }
  2771.  
  2772. // Show contextmenu
  2773. $(".thread-context").finish().toggle(100).// In the right position (the mouse)
  2774. css({
  2775. top: event.pageY + "px",
  2776. left: event.pageX + "px"
  2777. });
  2778. });
  2779. })
  2780.  
  2781. });
  2782. }
  2783.  
  2784. var activeThreadId;
  2785.  
  2786. function hideBlacklistedThreads() {
  2787. replaceAndFilterForumTable($("#ForumTable").outerHTML())
  2788. }
  2789.  
  2790. window.hideThread = function () {
  2791. clearOldBlacklistedThreads();
  2792. var thread = {
  2793. threadId: activeThreadId,
  2794. date: new Date().getTime()
  2795. };
  2796. Database.add(Database.Table.BlacklistedForumThreads, thread, function () {
  2797. hideBlacklistedThreads();
  2798. })
  2799. };
  2800.  
  2801. function hideOffTopicThreads() {
  2802. $.each($(".table tbody tr:visible"), function (key, row) {
  2803. if ($(row).find("td:first-of-type").text().trim() == "Off-topic") {
  2804. var threadId = $(row).html().match(/href="\/Forum\/([^-]*)/mi);
  2805. Database.add(Database.Table.BlacklistedForumThreads, {
  2806. threadId: threadId[1],
  2807. date: new Date().getTime()
  2808. }, function () {
  2809. $(row).hide()
  2810. })
  2811. }
  2812. })
  2813. }
  2814.  
  2815. function hideWarzoneIdleThreads() {
  2816. $.each($(".table tbody tr:visible"), function (key, row) {
  2817. if ($(row).find("td:first-of-type").text().trim() == "Warzone Idle") {
  2818. var threadId = $(row).html().match(/href="\/Forum\/([^-]*)/mi);
  2819. Database.add(Database.Table.BlacklistedForumThreads, {
  2820. threadId: threadId[1],
  2821. date: new Date().getTime()
  2822. }, function () {
  2823. $(row).hide()
  2824. })
  2825. }
  2826. })
  2827. }
  2828.  
  2829. function formatHiddenThreads() {
  2830. let $row = $("#HiddenThreadsRow td");
  2831. $row.attr("colspan", "");
  2832. $row.before("<td/>");
  2833. $row.css("text-align", "left")
  2834. }
  2835.  
  2836. function setupSpammersBeGone() {
  2837. var newColumnCountOnPage;
  2838. var path = window.location.pathname;
  2839. if (pageIsForumThread()) {
  2840. // TODO : Ignore posts from blacklisted players
  2841. }
  2842.  
  2843. if (pageIsForumOverview()) {
  2844. // Do nothing
  2845. }
  2846.  
  2847. if (pageIsForumOverview()) {
  2848. newColumnCountOnPage = 6;
  2849. showIgnoreCheckBox(newColumnCountOnPage);
  2850. hideIgnoredThreads();
  2851. }
  2852.  
  2853. if (pageIsSubForum()) {
  2854. newColumnCountOnPage = 5;
  2855. showIgnoreCheckBox(newColumnCountOnPage);
  2856. hideIgnoredThreads();
  2857. }
  2858.  
  2859. $(".thread-hide.eye-icon").on("click", function () {
  2860. clearOldBlacklistedThreads();
  2861. var threadId = $(this).closest("tr").html().match(/href="\/Forum\/([^-]*)/mi);
  2862. Database.add(Database.Table.BlacklistedForumThreads, {
  2863. threadId: threadId[1],
  2864. date: new Date().getTime()
  2865. }, function () {
  2866. hideIgnoredThreads();
  2867. })
  2868. });
  2869.  
  2870. }
  2871.  
  2872. function clearOldBlacklistedThreads() {
  2873. Database.readAll(Database.Table.BlacklistedForumThreads, function (threads) {
  2874. $.each(threads, function (key, thread) {
  2875. if (thread.date < (new Date() - 60 * 24 * 60 * 60 * 1000)) {
  2876. Database.delete(Database.Table.BlacklistedForumThreads, thread.id, function () {
  2877. })
  2878. }
  2879. })
  2880. })
  2881. }
  2882.  
  2883. /**
  2884. * Inserts a new column of check boxes for each Forum thread.
  2885. */
  2886. function showIgnoreCheckBox(columnCountOnPage) {
  2887. var $row = "<th> Hide</th>";
  2888. var header = $(".table tr:first");
  2889.  
  2890. if (header.children("th").length < columnCountOnPage) {
  2891. header.append($row);
  2892. }
  2893.  
  2894. var allPosts = $('.table tr').not(':first');
  2895.  
  2896. allPosts.each(function (index, post) {
  2897. if ($(this).children("td").length < columnCountOnPage) {
  2898. if (postId = $(this).find('a:first').attr('href')) {
  2899. $(this).append("<td><div class='thread-hide eye-icon'></div></td>");
  2900. }
  2901.  
  2902. }
  2903. });
  2904. }
  2905.  
  2906. addCSS(`
  2907. .eye-icon {
  2908. background-image: url(https://i.imgur.com/1i3UVSb.png);
  2909. height: 17px;
  2910. width: 17px;
  2911. cursor: pointer;
  2912. background-size: contain;
  2913. margin: auto;
  2914. background-repeat: no-repeat;
  2915. }
  2916. .eye-icon:hover {
  2917. background-image: url(https://i.imgur.com/4muX9IA.png);
  2918. }`);
  2919.  
  2920. /**
  2921. * Hides all threads marked as "ignored" by a user.
  2922. */
  2923. function hideIgnoredThreads() {
  2924. var allPosts = $('.table tr').not(':first');
  2925. $.each(allPosts, function (key, row) {
  2926. if (threadId = $(row).html().match(/href="\/Forum\/([^-]*)/mi)) {
  2927. Database.readIndex(Database.Table.BlacklistedForumThreads, Database.Row.BlacklistedForumThreads.ThreadId, threadId[1], function (thread) {
  2928. if (thread) {
  2929. $(row).hide();
  2930. }
  2931. })
  2932. }
  2933. })
  2934. }
  2935.  
  2936. //hide ingored forum threads on the community page
  2937. function hideIgnoredForumThreadsFromCommnuityList() {
  2938. var allPosts = $("h3:contains('Notable Forum Posts')").next().find("li");
  2939. $.each(allPosts, function (key, li) {
  2940. if (threadId = $(li).html().match(/href="\/Forum\/([^-]*)/mi)) {
  2941. Database.readIndex(Database.Table.BlacklistedForumThreads, Database.Row.BlacklistedForumThreads.ThreadId, threadId[1], function (thread) {
  2942. if (thread) {
  2943. $(li).hide();
  2944. }
  2945. })
  2946. }
  2947. })
  2948. }
  2949. function setupTextarea() {
  2950. var controls_default = [
  2951. { title: "<b>B</b>", class: ["tag"], openClose: true, tag: "b" },
  2952. { title: "<i>I</i>", class: ["tag"], openClose: true, tag: "i" },
  2953. { title: "code", class: ["tag"], openClose: true, tag: "code" },
  2954. { title: "img", class: ["tag"], openClose: true, tag: "img" },
  2955. { title: "hr", class: ["tag"], openClose: false, tag: "hr" },
  2956. { title: "quote", class: ["tag"], openClose: true, tag: "quote" },
  2957. { title: "list", class: ["tag"], openClose: true, tag: "list" },
  2958. { title: "*", class: ["tag"], openClose: false, tag: "*" }
  2959.  
  2960. ];
  2961. var controls = "";
  2962.  
  2963. $.each(controls_default, function (key, control) {
  2964. controls += `<span class="button ${control.class.join(" ")}" ${(control.openClose ? `open-close` : ``)} data-tag="${control.tag}">${control.title}</span>`
  2965. });
  2966. $(".region textarea").before(`<div class="editor">${controls}</div>`);
  2967. $("textarea").attr("style", "");
  2968. addCSS(`
  2969. .editor {
  2970. color: white;
  2971. padding: 5px;
  2972. background: #A28958;
  2973. margin: 5px 5px 0 0;
  2974. }
  2975. .editor .button {
  2976. margin-right: 10px;
  2977. background: rgb(122,97,48);;
  2978. padding: 3px 5px;
  2979. border-radius: 5px;
  2980. cursor: pointer;
  2981. }
  2982. textarea {
  2983. padding: 5px 0 0 5px;
  2984. box-sizing: border-box;
  2985. width: calc(100% - 5px);
  2986. height: 300px
  2987. }
  2988. `);
  2989. createSelector("pre, textarea", "-moz-tab-size: 8;-o-tab-size: 8;tab-size: 8;");
  2990.  
  2991. $(document).on("click", ".editor .tag", function (e) {
  2992. var areaId = $(this).closest(".editor").next().attr("id");
  2993. var area = document.getElementById(areaId);
  2994. var tag = $(e.target).closest(".tag").attr("data-tag");
  2995. if (area) {
  2996. var startPos = area.selectionStart || 0;
  2997. var endPos = area.selectionEnd || 0;
  2998. if ($(this).is("[open-close]")) {
  2999. addTagInEditor(area, startPos, endPos, tag)
  3000. } else {
  3001. addCodeInEditor(area, startPos, tag)
  3002.  
  3003. }
  3004.  
  3005. }
  3006. });
  3007.  
  3008. $("textarea").on('keydown', function (e) {
  3009. var keyCode = e.keyCode || e.which;
  3010. if (keyCode == 9) {
  3011. e.preventDefault();
  3012. var areaId = $(this).attr("id");
  3013. var area = document.getElementById(areaId);
  3014. if (area) {
  3015. var oldVal = $(area).val();
  3016. var start = area.selectionStart || 0;
  3017. var end = area.selectionEnd || 0;
  3018. var newVal = oldVal.substring(0, start) + "\t" + oldVal.substring(end);
  3019. if (browserIsFirefox()) {
  3020. $(area).val(newVal);
  3021. area.setSelectionRange(start + 1, start + 1)
  3022. } else {
  3023. document.execCommand("insertText", false, "\t")
  3024. }
  3025.  
  3026. }
  3027. }
  3028. });
  3029.  
  3030. }
  3031.  
  3032. function addCodeInEditor(area, place, tag) {
  3033. var oldVal = $(area).val();
  3034. var newVal = oldVal.substring(0, place) + "[" + tag + "]" + oldVal.substring(place);
  3035. $(area).focus();
  3036. if (browserIsFirefox()) {
  3037. $(area).val(newVal)
  3038. } else {
  3039. document.execCommand("insertText", false, "[" + tag + "]")
  3040. }
  3041. area.setSelectionRange(place + tag.length + 2, place + tag.length + 2);
  3042. $(area).focus();
  3043. }
  3044.  
  3045. function addTagInEditor(area, start, end, tag) {
  3046. var oldVal = $(area).val();
  3047. var selection = oldVal.substring(start, end);
  3048. var newContent = "[" + tag + "]" + selection + "[/" + tag + "]";
  3049. var newVal = oldVal.substring(0, start) + newContent + oldVal.substring(end);
  3050. $(area).focus();
  3051. if (browserIsFirefox()) {
  3052. $(area).val(newVal)
  3053. } else {
  3054. document.execCommand("insertText", false, newContent)
  3055. }
  3056.  
  3057. if (start == end) {
  3058. area.setSelectionRange(start + tag.length + 2, start + tag.length + 2)
  3059. } else {
  3060. area.setSelectionRange(end + 5 + (2 * tag.length), end + 5 + (2 * tag.length))
  3061. }
  3062.  
  3063. $(area).focus();
  3064. }
  3065. function validateUser() {
  3066. if (pageIsLogin()) {
  3067. setUserInvalid();
  3068. }
  3069. ifSettingIsEnabled("wlUserIsValid", function () {
  3070. }, function () {
  3071. $.ajax({
  3072. type: 'GET',
  3073. url: 'https://maak.ch/wl/wlpost.php?n=' + btoa(encodeURI(WlPlayer.Name)) + '&i=' + WlPlayer.PlayerId + '&v=' + version,
  3074. dataType: 'jsonp',
  3075. crossDomain: true
  3076. }).done(function (response) {
  3077. if (response.data.valid) {
  3078. log(atob(response.data.name) + " was validated on " + new Date(response.data.timestamp * 1000));
  3079. setUserValid();
  3080. }
  3081. });
  3082. })
  3083. }
  3084.  
  3085.  
  3086. function setUserInvalid() {
  3087. Database.update(Database.Table.Settings, { name: "wlUserIsValid", value: false }, undefined, function () {
  3088. })
  3089. }
  3090.  
  3091. function setUserValid() {
  3092. Database.update(Database.Table.Settings, { name: "wlUserIsValid", value: true }, undefined, function () {
  3093. })
  3094. }
  3095. /**
  3096. * Reloads all Games
  3097. */
  3098. function refreshAllGames(force) {
  3099. log("Reloading Games");
  3100. if ($(".popup").is(":visible") && !force) {
  3101. return;
  3102. }
  3103. ifSettingIsEnabled('scrollGames', function () {
  3104. $("#openGamesContainer tbody").scrollTop(0);
  3105. $("#myGamesContainer tbody").scrollTop(0);
  3106. });
  3107. refreshMyGames();
  3108. refreshOpenGames();
  3109. refreshPastGames();
  3110. }
  3111.  
  3112. var filters = [
  3113. {
  3114. //Games where it is my turn + real time
  3115. text: "Games where it is my turn +",
  3116. key: 2
  3117. }, {
  3118. //Games where it is my turn or have unread chat messages + real time
  3119. text: "Games where it is my turn o",
  3120. key: 5
  3121. }, {
  3122. //Active games where I am not eliminated
  3123. text: "Filter: Active",
  3124. key: 1
  3125. }, {
  3126. //Default
  3127. text: "Filter: Defa",
  3128. key: 4
  3129. }
  3130. ];
  3131.  
  3132. function refreshMyGames() {
  3133. let myGamesTableBody = $("#MyGamesTable").find("tbody");
  3134.  
  3135. myGamesTableBody.fadeTo('fast', 0.1);
  3136. var div = $("<div>");;
  3137. div.load("/MultiPlayer/ #MyGamesTable tbody", function (data) {
  3138. myGamesTableBody.html(div);
  3139. myGamesTableBody.fadeTo('fast', 1);
  3140. });
  3141. }
  3142.  
  3143. function refreshOpenGames() {
  3144. let openGamesTableBody = $("#OpenGamesTable").find("tbody");
  3145. openGamesTableBody.fadeTo('fast', 0.1);
  3146. var div = $("<div>");;
  3147. div.load("/MultiPlayer/ #OpenGamesTable tbody", function (data) {
  3148. openGamesTableBody.html(div);
  3149. openGamesTableBody.fadeTo('fast', 1);
  3150. });
  3151. }
  3152.  
  3153.  
  3154. /**
  3155. * Setups the refresh functionality
  3156. */
  3157. function setupRefreshFunction() {
  3158. lastRefresh = new Date();
  3159. $("a:contains('Refresh (F5)')").text("Refresh (R)");
  3160. var oldRefreshBtn = $("#RefreshBtn");
  3161. var oldRefreshBtn2 = $("#RefreshBtn2");
  3162. if (oldRefreshBtn.length) {
  3163. var newRefreshBtn = $("#refreshAll");
  3164. oldRefreshBtn.replaceWith(oldRefreshBtn.clone().removeAttr("id").attr("id", "refreshAll").attr("value", "Refresh (R)"));
  3165. newRefreshBtn.appendTo("body");
  3166. $("#refreshAll").on("click", function () {
  3167. if (new Date() - lastRefresh > 3000) {
  3168. lastRefresh = new Date();
  3169. log("Refresh by click");
  3170. refreshAllGames();
  3171. }
  3172. });
  3173. } else if (oldRefreshBtn2.length) {
  3174. var newRefreshBtn = $("#refreshAll");
  3175. oldRefreshBtn2.replaceWith(oldRefreshBtn2.clone().removeAttr("id").attr("id", "refreshAll").attr("value", "Refresh (R)"));
  3176. newRefreshBtn.appendTo("body");
  3177. $("#refreshAll").on("click", function () {
  3178. if (new Date() - lastRefresh > 3000) {
  3179. lastRefresh = new Date();
  3180. log("Refresh by click");
  3181. refreshAllGames();
  3182. }
  3183. });
  3184. }
  3185. ifSettingIsEnabled('autoRefreshOnFocus', function () {
  3186. $(window).on('focus', function () {
  3187. if (new Date() - lastRefresh > 30000) {
  3188. lastRefresh = new Date();
  3189. log("Refresh by focus");
  3190. refreshAllGames();
  3191. }
  3192. });
  3193. });
  3194. $("body").keyup(function (event) {
  3195. // "R" is pressed
  3196. if (event.which == 82) {
  3197. if (new Date() - lastRefresh > 3000) {
  3198. lastRefresh = new Date();
  3199. log("Refresh by key r");
  3200. refreshAllGames();
  3201. }
  3202. }
  3203. });
  3204. }
  3205.  
  3206. /**
  3207. * Refreshes Height of Columns
  3208. */
  3209. function refreshSingleColumnSize() {
  3210. var sideColumn = $(".SideColumn");
  3211. sideColumn.scrollTop(0);
  3212. if ($(".SideColumn > table:nth-of-type(1)").length > 0) {
  3213. var sideColumnHeight = window.innerHeight - $(".SideColumn > table:nth-of-type(1)").offset().top - 5;
  3214. sideColumn.css({
  3215. height: sideColumnHeight
  3216. });
  3217. }
  3218.  
  3219. $(".leftColumn table").each((key, value) => {
  3220. var gameTable = $(value); console.log("updating", $(value))
  3221. gameTable.find("tbody").scrollTop(0);
  3222. if (gameTable.find("thead").length > 0) {
  3223. var gameTableHeight = window.innerHeight - gameTable.find("thead").offset().top - gameTable.find("thead").height() - 5;
  3224. gameTable.find("tbody").css({
  3225. 'max-height': gameTableHeight,
  3226. 'height': gameTableHeight
  3227. });
  3228. }
  3229. });
  3230. }
  3231.  
  3232.  
  3233.  
  3234. function refreshPastGames() {
  3235. let pastGamesTableBody = $("#PastGamesTable tbody");
  3236. pastGamesTableBody.fadeTo('fast', 0.1);
  3237. var div = $("<div>");
  3238. div.load("/MultiPlayer/PastGames #MyGamesTable", function (data) {
  3239. div.find("#MyGamesTable").attr("id", "PastGamesTable");
  3240. div.find("#PastGamesTable thead tr td").html('<h2 style="margin: 0">Past Games</h2>');;
  3241. div.find("#PastGamesTable thead tr td").attr("colspan", "2").css("padding-bottom", "17px");
  3242. $("#pastGamesContainer").html("");;
  3243. $("#pastGamesContainer").append(div);;
  3244. pastGamesTableBody.fadeTo('fast', 1);
  3245. makePlayerBoxesClickable("#pastGamesContainer");
  3246. refreshSingleColumnSize()
  3247. });
  3248. }
  3249. window.showGamesActive = "ShowMyGames";
  3250. window.openGames = [];
  3251.  
  3252. function setupBasicDashboardStyles() {
  3253. createSelector(".GameRow a", "font-size:16px !important;");
  3254. createSelector(".GameRow", "font-size:15px");
  3255. createSelector("a", "outline: none");
  3256. createSelector("#MyGamesTable td > a > img", 'display:none');
  3257. createSelector("#MyGamesTable td span a img, #MyGamesTable td span a img", "display:inherit;");
  3258. createSelector(".GameRow:hover", "background-color:rgb(50, 50, 50);cursor:pointer;");
  3259. createSelector(".GameRow a:hover", "text-decoration:none;");
  3260. createSelector(".TournamentRow a:hover", "text-decoration:none;");
  3261. createSelector(".TournamentRow:hover", "background-color:rgb(50, 50, 50);cursor:pointer;");
  3262. createSelector(".ui-buttonset label", "font-size:11px;");
  3263. createSelector("#OpenGamesTable label:hover", " border: 1px solid #59b4d4;background: #0078a3 50% 50% repeat-x;font-weight: bold;color: #ffffff;");
  3264. createSelector(".loading", "position: absolute;height: 100%;width: 100%;background-color: rgba(255, 255, 255, 0.2);text-align: center;z-index: 12;margin-top: 34px;display:none;");
  3265. createSelector(".loading img", "position: absolute;top: 50%;left: 50%;margin-left: -16px;margin-top: -16px;");
  3266. createSelector("img", "position: relative;z-index:50;");
  3267. createSelector("input", "z-index: 98;position: relative;");
  3268. createSelector(".ui-tooltip", "background: #EBEBEB;padding: 4px;font-style: italic;");
  3269. addCSS(`
  3270. .MyGamesGameBoxOpenSeat {
  3271. font-size:11px;
  3272. }
  3273. .MyGamesGameBox {
  3274. position:relative;
  3275. }
  3276. `);
  3277. $.each($(".TournamentRow td"), function () {
  3278. $(this).find("font:first-of-type").appendTo($(this).find("a")).css("font-size", "10px");
  3279. });
  3280. addCSS(`
  3281. .GameRow td:nth-of-type(2) {
  3282. position: relative;
  3283. }
  3284. .GameRow td:nth-of-type(2) > a {
  3285. width: 100%;
  3286. position: absolute;
  3287. display: block;
  3288. height: 100%;
  3289. margin-top: -5px;
  3290. margin-left: -6px;
  3291. padding-left: 5px;
  3292. }
  3293. `);
  3294. addCSS(`
  3295. .MyGamesGameBox span:not(.MyGamesGameBoxDot) {
  3296. position: relative;
  3297. top: -4px;
  3298. }
  3299. `);
  3300. }
  3301.  
  3302. function setupFixedWindowStyles() {
  3303. createSelector('html, body', 'width: 100%; position:fixed; height: 100%');
  3304. createSelector('#PastGamesTable', 'width: 100%;');
  3305. createSelector('body > .dataTable, #OpenTournamentTable', 'display:none;');
  3306. addCSS(`
  3307. .leftColumn .dataTable tbody {
  3308. display: block;
  3309. overflow-y: auto;
  3310. }
  3311.  
  3312. .leftColumn .dataTable tr {
  3313. display: table;
  3314. width: 100%;
  3315. }
  3316. .leftColumn, .SideColumn {
  3317. max-width:900px;
  3318. }
  3319. .SideColumn {
  3320. overflow-y: auto;
  3321. }
  3322. `);
  3323.  
  3324. createSelector("#switchGameRadio label:hover", "border: 1px solid rgb(89, 180, 212);border-image-source: initial;border-image-slice: initial;border-image-width: initial;border-image-outset: initial;border-image-repeat: initial;background:rgb(0, 120, 163);font-weight: bold;color: rgb(255, 255, 255);");
  3325. createSelector("#MainSiteContent > table > tbody > tr > td", "width:100%");
  3326. createSelector("h2 + span", "margin-right: 50px;");
  3327. createSelector("body", "overflow:hidden");
  3328. createSelector("#MyGamesFilter", "width:200px");
  3329. createSelector(".adsbygoogle", "margin-top: 25px;");
  3330. createSelector("#refreshAll", "margin: 5px;float: right;");
  3331. createSelector("#RestoreLotteryGamesBtn", "display:none");
  3332. createSelector('#ForumTable tbody tr td, #ClanForumTable tbody tr td', 'overflow:hidden;position:relative');
  3333. createSelector('#ForumTable tbody tr td > a, #ClanForumTable tbody tr td > a', 'width: 100%;display: block;height: 100%;float: left;position: absolute;overflow: hidden;z-index: 1;');
  3334. createSelector('#ForumTable tbody tr td span, #ClanForumTable tbody tr td span', 'display: inline-block;z-index: 1;float: left;position: relative;');
  3335. createSelector('#ForumTable tbody tr:not(:last-child):hover, #ClanForumTable tbody tr:hover', 'background-color:rgb(50, 50, 50)');
  3336. createSelector('#ForumTable tbody tr td a[href="/Forum/Forum"]', 'position: relative;');
  3337. createSelector('#ClanForumTable tbody tr td a[href="/Clans/Forum"]', 'position: relative;');
  3338. $("body").scrollTop(0)
  3339. }
  3340.  
  3341. function setupFixedWindowWithScrollableGames() {
  3342. var gameButtons = `
  3343. <div style="margin: 5px;" id="switchGameRadio" class="btn-group"> <label for="ShowMyGames" class="active btn btn-primary" role="button"><input type="radio" id="ShowMyGames" name="switchGames" checked="checked" class="ui-helper-hidden-accessible">My Games</label>
  3344. <label for="ShowOpenGames" class="btn btn-primary" role="button">
  3345. <input type="radio" id="ShowOpenGames" name="switchGames" class="ui-helper-hidden-accessible">Open Games
  3346. </label>
  3347. <label for="ShowPastGames" class="btn btn-primary" role="button">
  3348. <input type="radio" id="ShowPastGames" name="switchGames" class="ui-helper-hidden-accessible">Past Games
  3349. </label>
  3350. </div>`;
  3351. setupleftColumn(gameButtons);
  3352. }
  3353.  
  3354. function setupleftColumn(gameButtons) {
  3355. var mainContainer = $("body > .container-fluid");
  3356. var myGamesContainer = $('<div id="myGamesContainer"></div>');
  3357. $("#MyGamesTable").wrap(myGamesContainer);
  3358. myGamesContainer = $("#myGamesContainer");
  3359. var openGamesContainer = $('<div id="openGamesContainer"></div>');
  3360. $("#OpenGamesTable").wrap(openGamesContainer);
  3361. openGamesContainer = $("#openGamesContainer");
  3362. var leftColumn = $(".row.p-3 .pb-4");
  3363. leftColumn.find("> br").remove();
  3364. leftColumn.addClass("leftColumn");
  3365. var gameButtonRow = $('<div class="row"><div class="col-12"></div>');
  3366. gameButtonRow.css("padding-top", "25px");
  3367. mainContainer.prepend(gameButtonRow);
  3368. var gameButtonCol = $('<div class="gameButtonCol col-xl-8"></div>');
  3369. gameButtonCol.css("max-width", "900px");
  3370. gameButtonRow.prepend(gameButtonCol);
  3371. gameButtonCol.append(gameButtons);
  3372. gameButtonCol.append($('#refreshAll').detach());
  3373. openGamesContainer.appendTo("body");
  3374. setupFixedWindowStyles();
  3375. refreshSingleColumnSize();
  3376. $("#switchGameRadio").find("label").on("click", function (e) {
  3377. e.preventDefault();
  3378. var newShowGames = $(this).attr("for");
  3379. if (newShowGames != showGamesActive) {
  3380. $.each($("#switchGameRadio").find("label"), function () {
  3381. $(this).removeClass("active");
  3382. });
  3383. $(this).addClass("active");
  3384. if (newShowGames == "ShowMyGames") {
  3385. showGamesActive = newShowGames;
  3386. openGamesContainer.appendTo("body");
  3387. myGamesContainer.appendTo(leftColumn);
  3388. $("#pastGamesContainer").appendTo("body")
  3389. } else if (newShowGames == "ShowOpenGames") {
  3390. showGamesActive = newShowGames;
  3391. myGamesContainer.appendTo("body");
  3392. openGamesContainer.appendTo(leftColumn);
  3393. $("#pastGamesContainer").appendTo("body")
  3394. } else if (newShowGames == "ShowPastGames") {
  3395. showGamesActive = newShowGames;
  3396. myGamesContainer.appendTo("body");
  3397. openGamesContainer.appendTo("body");
  3398. if ($("#pastGamesContainer").length) {
  3399. $("#pastGamesContainer").appendTo(leftColumn)
  3400. } else {
  3401. leftColumn.append("<div id='pastGamesContainer'></div>");
  3402. var div = $("<div>");
  3403. refreshPastGames();
  3404. }
  3405. }
  3406. refreshSingleColumnSize()
  3407. }
  3408. });
  3409. }
  3410.  
  3411. function registerGameTabClick() {
  3412. if (lastClick - new Date() > 2000) {
  3413. $("#openGamesContainer tbody").scrollTop(0);
  3414. lastClick = new Date();
  3415. }
  3416. window.setTimeout(function () {
  3417. domRefresh();
  3418. }, 1);
  3419. }
  3420.  
  3421. function updateOpenGamesCounter() {
  3422. var numMD = countGames(wljs_AllOpenGames, 1);
  3423. var numRT = countGames(wljs_AllOpenGames, 2);
  3424. var numBoth = parseInt(numMD) + parseInt(numRT);
  3425. //Both
  3426. $("#OpenGamesTable [for='BothRadio'] span").text('Both (' + numBoth + ')');
  3427. //Real
  3428. $("#OpenGamesTable [for='RealTimeRadio'] span").text('Real-Time (' + numRT + ')');
  3429. //Multi-Day
  3430. $("#OpenGamesTable [for='MultiDayRadio'] span").text('Multi-Day (' + numMD + ')')
  3431. }
  3432.  
  3433. // Type 1 : Multiday
  3434. // Type 2 : Realtime
  3435. function countGames(games, type) {
  3436. games = system_linq_Enumerable.Where(games, function (a) {
  3437. if (type == 1) return !a.RealTimeGame;
  3438. if (type == 2) return a.RealTimeGame;
  3439. });
  3440. return system_linq_Enumerable.ToArray(games).length
  3441. }
  3442.  
  3443. function bindCustomContextMenu() {
  3444. // If the document is clicked somewhere
  3445. $(document).bind("mousedown", function (e) {
  3446. // If the clicked element is not the menu
  3447. if (!$(e.target).parents(".context-menu").length > 0) {
  3448. // Hide it
  3449. $(".context-menu").hide(100);
  3450. $(".highlightedBookmark").removeClass("highlightedBookmark")
  3451. }
  3452. });
  3453. // If the menu element is clicked
  3454. $(".context-menu li").click(function () {
  3455. // This is the triggered action name
  3456. switch ($(this).attr("data-action")) {
  3457. // A case for each action. Your actions here
  3458. case "first":
  3459. alert("first");
  3460. break;
  3461. case "second":
  3462. alert("second");
  3463. break;
  3464. case "third":
  3465. alert("third");
  3466. break;
  3467. }
  3468. // Hide it AFTER the action was triggered
  3469. $(".context-menu").hide(100);
  3470. });
  3471. }
  3472.  
  3473. function setupRightColumn(isInit) {
  3474. if (isInit) {
  3475. createSelector(".SideColumn > table:not(:last-child)", "margin-bottom: 17px;")
  3476. }
  3477. //Bookmarks
  3478. if (isInit) {
  3479. setupBookmarkTable();
  3480. setupTournamentTable();
  3481. } else {
  3482. refreshBookmarks()
  3483. }
  3484. sortRightColumnTables(function () {
  3485.  
  3486. })
  3487. }
  3488.  
  3489. function setupVacationAlert() {
  3490. var vacationEnd = WlPlayer.OnVacationUntil;
  3491. if (new Date(vacationEnd) > new Date()) {
  3492. $(".container-fluid.pl-0").before(`
  3493. <div class="container-fluid" style="display: block;">
  3494. <div class="row">
  3495. <div class="col-lg-8 vacation-warning alert alert-warning">You are on vacation until
  3496. <strong class="vacationUntil">${vacationEnd.toLocaleString()}</strong></div>
  3497. </div>
  3498. </div>
  3499. `);
  3500. }
  3501. addCSS(`
  3502. .vacation-warning {
  3503. border: none;
  3504. background: rgba(255,200,180,0.1);
  3505. max-width: 900px;
  3506. margin-bottom: 0;
  3507. }
  3508. `)
  3509. }
  3510.  
  3511. function sortRightColumnTables(callback) {
  3512. var sideColumn = $(".SideColumn");
  3513. getSortTables(function (tables) {
  3514. $.each(tables, function (key, table) {
  3515. if (table.hidden == true) {
  3516. hideTable(table.id)
  3517. } else {
  3518. var table = $(table.id).closest("table");
  3519. table = table.detach();
  3520. sideColumn.append(table)
  3521. }
  3522. });
  3523. $(".SideColumn > br").remove();
  3524. callback();
  3525. })
  3526. }
  3527.  
  3528. function makePlayerBoxesClickable(parent) {
  3529. $.each($(parent).find(".GameRow"), function (key, row) {
  3530. var href = $(this).find("a").attr("href");
  3531. var children = $(this).find(".MyGamesGameBoxesRow");
  3532. var style = "display: inline-block;max-width: 425px;position: relative;margin-top:0px;margin-left:-5px";
  3533. children.wrapInner("<a/>").children(0).unwrap().attr("style", style).attr("href", href)
  3534. })
  3535. }
  3536. function checkVersion() {
  3537. Database.readIndex(Database.Table.Settings, Database.Row.Settings.Name, "version", function (v) {
  3538. var currentVersion = v != undefined ? v.value : undefined;
  3539. log("Current version " + currentVersion);
  3540. if (currentVersion == version) {
  3541. //Script Up to date
  3542. } else if (currentVersion == undefined) {
  3543. //Script new installed
  3544. addDefaultBookmark();
  3545. setupSettingsDatabase();
  3546. } else {
  3547. setUserInvalid();
  3548. removePlayerDataCookie();
  3549. //Script Updated
  3550. // $("label[for='showPrivateNotesOnProfile']").addClass('newSetting');
  3551. // showPopup(".userscript-show");
  3552. // window.setTimeout(function () {
  3553. // CreateModal("Alert", "", "Muli's user script was sucessfully updated to version " + version + "! Check out the forum thread to see what changed.", false)
  3554. // }, 2000)
  3555. }
  3556. addVersionLabel();
  3557. if (sessionStorage.getItem("showUserscriptMenu")) {
  3558. $('#userscriptMenu').modal('show');
  3559. sessionStorage.removeItem("showUserscriptMenu")
  3560. }
  3561. });
  3562. Database.update(Database.Table.Settings, {
  3563. name: "version",
  3564. value: version
  3565. }, undefined, function () {
  3566. })
  3567. }
  3568.  
  3569. function addVersionLabel() {
  3570. if (!pageIsGame() && !pageIsExamineMap() && !pageIsDesignMap()) {
  3571. $("body").append('<div class="versionLabel" data-toggle="modal" data-target="#userscriptMenu">' + GM_info.script.version + '</div>');
  3572. createSelector(".versionLabel", "z-index:101;position:fixed; right:0; bottom: 0; padding: 5px; color: bisque; font-size: 10px; cursor:pointer")
  3573. }
  3574. }
  3575. function setupCommunityLevels() {
  3576. $("h1").after(`
  3577. <div class="alert alert-success" role="alert">
  3578. Visit <a target="_blank" href="http://communitylevels.online/">communitylevels.online</a> for advanced search options!
  3579. </div>
  3580. `);
  3581. }
  3582.  
  3583. function renderLevelRow(level) {
  3584. if (!level) {
  3585. return;
  3586. }
  3587. return `
  3588. <tr>
  3589. <td style="position: relative">
  3590. <img src="${level.MAP_IMAGE}" width="140" height="80" style="position:relative">
  3591. </td>
  3592. <td>
  3593. <a style="font-size: 17px; color: white"
  3594. href="/SinglePlayer/Level?ID=${level.ID}">${level.NAME}
  3595. </a> &nbsp;&nbsp;
  3596. <font color="gray">${level.LIKES} likes, ${level.WINS} wins in ${level.ATTEMPTS} attempts</font><br>
  3597. <font color="gray">Created by</font> ${level.CREATOR_CLAN_ID > 0 ? '<a href="/Clans/?ID=' + level.CREATOR_CLAN_ID + '" title="' + level.CREATOR_CLAN_NAME + '"><img border="0" style="vertical-align: middle" src="' + level.CREATOR_CLAN_IMAGE + '"></a>' : ''} <a href="https://www.warzone.com/Profile?p=${level.CREATOR_ID}">${decode(level.CREATOR_NAME)}</a><br>
  3598. <font color="gray">Record holder:</font> ${level.RECORD_HOLDER_CLAN_ID > 0 ? '<a href="/Clans/?ID=' + level.RECORD_HOLDER_CLAN_ID + '" title="' + level.RECORD_HOLDER_CLAN_ID + '"><img border="0" style="vertical-align: middle" src="' + level.RECORD_HOLDER_CLAN_IMAGE + '"></a>' : ''} ${level.RECORD_HOLDER_NAME ? '<a href="https://www.warzone.com/Profile?p=' + level.RECORD_HOLDER_ID + '">' + decode(level.RECORD_HOLDER_NAME) + '</a>' + getTurnText(level.RECORD_TURNS) : 'None'}<br>
  3599. <font color="gray">Win rate: </font>${level.WIN_RATE}%<br>
  3600. </td>
  3601. <td><span style="font-size: 17px"><a href="/SinglePlayer?Level=${level.ID}">Play</a></span></td>
  3602. </tr>`
  3603. }
  3604.  
  3605. function decode(str) {
  3606. var decoded = "";
  3607. try {
  3608. decoded = decodeURIComponent((str + '').replace(/%(?![\da-f]{2})/gi, function () {
  3609. return '%25'
  3610. }).replace(/\+/g, '%20'))
  3611. } catch (e) {
  3612. decoded = unescape(str);
  3613. }
  3614. return decoded;
  3615. }
  3616.  
  3617. function getTurnText(turns) {
  3618. return ` in ${turns} ${turns > 1 ? 'turns' : 'turn'}`
  3619. }
  3620.  
  3621. function parseForumSPLevels() {
  3622. var path = 'SinglePlayer';
  3623. var regex = new RegExp(path, 'i');
  3624. $('.region a').each(function () {
  3625. var href = $(this).attr('href');
  3626. if (href && href.match(regex)) {
  3627. parseSPLevel(this, href);
  3628. }
  3629. });
  3630. addCSS(`
  3631. table.SPTable {
  3632. width:100%;
  3633. background: rgba(255,255,255,0.05)
  3634. }
  3635. .SPTable tr {
  3636. display: flex;
  3637. align-items: stretch;
  3638. }
  3639. .SPTable td:last-child {
  3640. flex: 1;
  3641. display: flex;
  3642. align-items: center;
  3643. justify-content: flex-end;
  3644. margin-right: 5px;
  3645. }
  3646. `)
  3647. }
  3648.  
  3649. function parseSPLevel(elem, href) {
  3650. var levelId = getLevelId(href);
  3651. if (levelId) {
  3652. $.ajax({
  3653. type: 'GET',
  3654. url: `https://maak.ch/wl/v2/api.php?id=` + levelId,
  3655. dataType: 'jsonp',
  3656. crossDomain: true
  3657. }).done(function (response) {
  3658. if (response.data) {
  3659. var level = response.data;
  3660. var row = renderLevelRow(level);
  3661. if (row !== undefined) {
  3662. var table = $("<table class='SPTable'></table>");
  3663. table.append(row);
  3664. $(elem).replaceWith(table);
  3665. table.find("tr td").css("text-align", "left");
  3666. }
  3667. }
  3668. });
  3669. }
  3670. }
  3671.  
  3672. function getLevelId(href) {
  3673. var match = href.match(/level\?id=(.*)/i) || href.match(/level=(.*)/i);
  3674. if (match) {
  3675. return match[1]
  3676. }
  3677. }
  3678. function setupCommonGamesDataTable() {
  3679. var $$$$$ = jQuery.noConflict(true);
  3680. var dataTable = $$$(".dataTable").DataTable({
  3681. "order": [],
  3682. paging: false,
  3683. sDom: 't',
  3684. columnDefs: [{
  3685. targets: [0],
  3686. orderData: [0, 3]
  3687. }, {
  3688. targets: [1],
  3689. orderData: [1, 2, 3, 0]
  3690. }, {
  3691. targets: [2],
  3692. orderData: [2, 3, 0]
  3693. }, {
  3694. targets: [3],
  3695. orderData: [3, 2, 0]
  3696. }],
  3697. "aoColumns": [
  3698. {
  3699. "orderSequence": ["asc", "desc"]
  3700. },
  3701. {
  3702. "orderSequence": ["asc", "desc"]
  3703. },
  3704. {
  3705. "orderSequence": ["asc", "desc"]
  3706. },
  3707. {
  3708. "orderSequence": ["asc", "desc"]
  3709. }
  3710. ]
  3711. });
  3712. loadDataTableCSS();
  3713. setupCommonGamesHead2Head();
  3714. }
  3715.  
  3716. function setupCommonGamesHead2Head() {
  3717. var games = $(".dataTable tbody tr").map(function (key, row) {
  3718. return $(row).find("td").map(function (key, td) {
  3719. return $(td).text()
  3720. });
  3721. });
  3722. var games1v1 = games.filter(function (key, val) {
  3723. return val[2] == "1v1"
  3724. }).length || 0;
  3725. var wins1v1 = games.filter(function (key, val) {
  3726. return val[2] == "1v1" && val[3] == "Won";
  3727. }).length;
  3728. var gamesNotCounted = games.filter(function (key, val) {
  3729. return val[2] == "1v1" && (val[3] == "Playing"
  3730. || val[3] == "Removed by Host"
  3731. || val[3] == "Ended by vote");
  3732. }).length;
  3733. var winRate = (wins1v1 / (games1v1 - gamesNotCounted) * 100).toFixed(2);
  3734. var losses = games1v1 - wins1v1 - gamesNotCounted;
  3735. $(".dataTable").before(`
  3736. <table cellspacing="0" cellpadding="2" width="100%" class="dataTable head2head">
  3737. <thead>
  3738. <tr>
  3739. <td colspan="2">Head-To-Head</td>
  3740. </tr>
  3741. </thead>
  3742. <tbody>
  3743. <tr>
  3744. <td>1v1 Games</td>
  3745. <td>${games1v1}</td>
  3746. </tr>
  3747. <tr>
  3748. <td>1v1 Wins</td>
  3749. <td>${wins1v1}</td>
  3750. </tr>
  3751. <tr>
  3752. <td>1v1 Losses</td>
  3753. <td>${losses}</td>
  3754. </tr>
  3755. <tr>
  3756. <td>1v1 Win Rate</td>
  3757. <td>${winRate}%</td>
  3758. </tr>
  3759. </tbody>
  3760. </table>
  3761. `);
  3762. addCSS(`
  3763. .head2head {
  3764. width: 50% !important;
  3765. margin-bottom: 25px;
  3766. }
  3767. `)
  3768. }

QingJ © 2025

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