diff --git a/dist/extendedPlayerProfile.js b/dist/extendedPlayerProfile.js index 155c3f9..8f758a3 100644 --- a/dist/extendedPlayerProfile.js +++ b/dist/extendedPlayerProfile.js @@ -117,7 +117,201 @@ parcelRequire = (function (modules, cache, entry, globalName) { } return newRequire; -})({"Ph2E":[function(require,module,exports) { +})({"VYL5":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = toInteger; + +function toInteger(dirtyNumber) { + if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) { + return NaN; + } + + var number = Number(dirtyNumber); + + if (isNaN(number)) { + return number; + } + + return number < 0 ? Math.ceil(number) : Math.floor(number); +} +},{}],"kK6Q":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = requiredArgs; + +function requiredArgs(required, args) { + if (args.length < required) { + throw new TypeError(required + ' argument' + (required > 1 ? 's' : '') + ' required, but only ' + args.length + ' present'); + } +} +},{}],"KYJg":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = toDate; + +var _index = _interopRequireDefault(require("../_lib/requiredArgs/index.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * @name toDate + * @category Common Helpers + * @summary Convert the given argument to an instance of Date. + * + * @description + * Convert the given argument to an instance of Date. + * + * If the argument is an instance of Date, the function returns its clone. + * + * If the argument is a number, it is treated as a timestamp. + * + * If the argument is none of the above, the function returns Invalid Date. + * + * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`. + * + * @param {Date|Number} argument - the value to convert + * @returns {Date} the parsed date in the local time zone + * @throws {TypeError} 1 argument required + * + * @example + * // Clone the date: + * const result = toDate(new Date(2014, 1, 11, 11, 30, 30)) + * //=> Tue Feb 11 2014 11:30:30 + * + * @example + * // Convert the timestamp to date: + * const result = toDate(1392098430000) + * //=> Tue Feb 11 2014 11:30:30 + */ +function toDate(argument) { + (0, _index.default)(1, arguments); + var argStr = Object.prototype.toString.call(argument); // Clone the date + + if (argument instanceof Date || typeof argument === 'object' && argStr === '[object Date]') { + // Prevent the date to lose the milliseconds when passed to new Date() in IE10 + return new Date(argument.getTime()); + } else if (typeof argument === 'number' || argStr === '[object Number]') { + return new Date(argument); + } else { + if ((typeof argument === 'string' || argStr === '[object String]') && typeof console !== 'undefined') { + // eslint-disable-next-line no-console + console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as arguments. Please use `parseISO` to parse strings. See: https://git.io/fjule"); // eslint-disable-next-line no-console + + console.warn(new Error().stack); + } + + return new Date(NaN); + } +} +},{"../_lib/requiredArgs/index.js":"kK6Q"}],"lQIY":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = addDays; + +var _index = _interopRequireDefault(require("../_lib/toInteger/index.js")); + +var _index2 = _interopRequireDefault(require("../toDate/index.js")); + +var _index3 = _interopRequireDefault(require("../_lib/requiredArgs/index.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * @name addDays + * @category Day Helpers + * @summary Add the specified number of days to the given date. + * + * @description + * Add the specified number of days to the given date. + * + * ### v2.0.0 breaking changes: + * + * - [Changes that are common for the whole library](https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#Common-Changes). + * + * @param {Date|Number} date - the date to be changed + * @param {Number} amount - the amount of days to be added. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. + * @returns {Date} the new date with the days added + * @throws {TypeError} 2 arguments required + * + * @example + * // Add 10 days to 1 September 2014: + * var result = addDays(new Date(2014, 8, 1), 10) + * //=> Thu Sep 11 2014 00:00:00 + */ +function addDays(dirtyDate, dirtyAmount) { + (0, _index3.default)(2, arguments); + var date = (0, _index2.default)(dirtyDate); + var amount = (0, _index.default)(dirtyAmount); + + if (isNaN(amount)) { + return new Date(NaN); + } + + if (!amount) { + // If 0 days, no-op to avoid changing times in the hour before end of DST + return date; + } + + date.setDate(date.getDate() + amount); + return date; +} +},{"../_lib/toInteger/index.js":"VYL5","../toDate/index.js":"KYJg","../_lib/requiredArgs/index.js":"kK6Q"}],"mRRL":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = subDays; + +var _index = _interopRequireDefault(require("../_lib/toInteger/index.js")); + +var _index2 = _interopRequireDefault(require("../addDays/index.js")); + +var _index3 = _interopRequireDefault(require("../_lib/requiredArgs/index.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * @name subDays + * @category Day Helpers + * @summary Subtract the specified number of days from the given date. + * + * @description + * Subtract the specified number of days from the given date. + * + * ### v2.0.0 breaking changes: + * + * - [Changes that are common for the whole library](https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#Common-Changes). + * + * @param {Date|Number} date - the date to be changed + * @param {Number} amount - the amount of days to be subtracted. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. + * @returns {Date} the new date with the days subtracted + * @throws {TypeError} 2 arguments required + * + * @example + * // Subtract 10 days from 1 September 2014: + * var result = subDays(new Date(2014, 8, 1), 10) + * //=> Fri Aug 22 2014 00:00:00 + */ +function subDays(dirtyDate, dirtyAmount) { + (0, _index3.default)(2, arguments); + var amount = (0, _index.default)(dirtyAmount); + return (0, _index2.default)(dirtyDate, -amount); +} +},{"../_lib/toInteger/index.js":"VYL5","../addDays/index.js":"lQIY","../_lib/requiredArgs/index.js":"kK6Q"}],"Ph2E":[function(require,module,exports) { "use strict"; Object.defineProperty(exports, "__esModule", { @@ -158,6 +352,79 @@ var _default = function _default() { }; exports.default = _default; +},{}],"m41w":[function(require,module,exports) { +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.generatePaginationItems = exports.calcNumberOfPages = exports.getPage = exports.setPage = void 0; +const ATTRIBUTE = 'data-page'; + +const setPage = function setPage(el) { + let page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + + if (!el instanceof HTMLElement) { + throw new Error('Expected HTMLElement as the first argument'); + } + + page = parseInt(page); + + if (typeof page !== 'number' || isNaN(page)) { + throw new Error('Expected number or string as the second argument'); + } + + el.setAttribute(ATTRIBUTE, page + ''); +}; + +exports.setPage = setPage; + +const getPage = el => { + if (!el instanceof HTMLElement) { + return 0; + } + + return parseInt(el.getAttribute(ATTRIBUTE)); +}; + +exports.getPage = getPage; + +const calcNumberOfPages = (total, limit) => { + if (typeof total !== 'number') { + throw new Error('Expected number as the first argument'); + } + + if (typeof limit !== 'number') { + throw new Error('Expected number as the second argument'); + } + + return total > 0 ? Math.ceil(total / limit) : 1; +}; + +exports.calcNumberOfPages = calcNumberOfPages; + +const generatePaginationItems = function generatePaginationItems() { + let { + total, + limit, + marginRight = 3, + currentPage = 0 + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + const numberOfPages = calcNumberOfPages(total, limit); + const paginationItems = []; + + for (let i = 1; i <= numberOfPages; i++) { + if (i === currentPage) { + paginationItems.push(">").concat(i, "<")); + } else { + paginationItems.push("").concat(i, "")); + } + } + + return paginationItems; +}; + +exports.generatePaginationItems = generatePaginationItems; },{}],"tQUs":[function(require,module,exports) { "use strict"; @@ -435,8 +702,12 @@ exports.setItem = setItem; },{}],"yRop":[function(require,module,exports) { "use strict"; +var _subDays = _interopRequireDefault(require("date-fns/subDays")); + var _requestCreator = _interopRequireDefault(require("./libs/requestCreator")); +var _pagination = require("./libs/pagination"); + var _getIDFromURL = _interopRequireDefault(require("./utils/getIDFromURL")); var _getCurrentServer = _interopRequireDefault(require("./utils/getCurrentServer")); @@ -453,6 +724,12 @@ var _localStorage = require("./utils/localStorage"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + // ==UserScript== // @name Extended Player Profile // @namespace https://github.com/tribalwarshelp/scripts @@ -479,6 +756,9 @@ const PLAYER_QUERY = "\n query pageData($server: String!, $id: Int!, $filter: const TRIBE_CHANGES_QUERY = "\n query tribeChanges($server: String!, $filter: TribeChangeFilter!) {\n tribeChanges(server: $server, filter: $filter) {\n total\n items {\n oldTribe {\n id\n tag\n }\n newTribe {\n id\n tag\n }\n createdAt\n }\n }\n }\n"; const TRIBE_CHANGES_PAGINATION_CONTAINER_ID = 'tribeChangesPagination'; const TRIBE_CHANGES_PER_PAGE = 15; +const PLAYER_HISTORY_AND_PLAYER_DAILY_STATS_QUERY = "\nquery playerHistoryAndPlayerDailyStats($server: String!,\n $playerHistoryFilter: PlayerHistoryFilter!,\n $dailyPlayerStatsFilter: DailyPlayerStatsFilter!) {\n playerHistory(server: $server, filter: $playerHistoryFilter) {\n total\n items {\n totalVillages\n points\n rank\n scoreAtt\n rankAtt\n scoreDef\n rankDef\n scoreSup\n rankSup\n scoreTotal\n rankTotal\n tribe {\n id\n tag\n }\n createDate\n }\n }\n dailyPlayerStats(server: $server, filter: $dailyPlayerStatsFilter) {\n items {\n points\n scoreAtt\n scoreAtt\n scoreDef\n scoreSup\n scoreTotal\n villages\n createDate\n }\n }\n}\n"; +const PLAYER_HISTORY_PAGINATION_CONTAINER_ID = 'playerHistoryPagination'; +const PLAYER_HISTORY_PER_PAGE = 15; const profileInfoTBody = document.querySelector('#player_info > tbody'); const actionsContainer = PLAYER_ID === CURRENT_PLAYER_ID ? profileInfoTBody : document.querySelector('#content_value > table > tbody > tr > td:nth-child(1) > table:nth-child(2) > tbody'); const otherElementsContainer = document.querySelector(PLAYER_ID === CURRENT_PLAYER_ID ? '#content_value > table:nth-child(7) > tbody > tr > td:nth-child(2)' : '#content_value > table > tbody > tr > td:nth-child(2)'); @@ -609,7 +889,7 @@ const renderTodaysStats = stats => { const statIncreaseStyle = 'color: #000; background-color: #0f0'; const statDecreaseStyle = 'color: #000; background-color: #f00'; - todaysStats.innerHTML = "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Today's stats\n
\n Points:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.points).toLocaleString(), "\n
\n Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rank), "\n
\n Villages:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.villages).toLocaleString(), "\n
\n ODA:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreAtt).toLocaleString(), "\n
\n Rank ODA:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankAtt), "\n
\n ODD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreDef).toLocaleString(), "\n
\n Rank ODD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankDef), "\n
\n ODS:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreSup).toLocaleString(), "\n
\n Rank ODS:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankSup), "\n
\n OD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreTotal).toLocaleString(), "\n
\n Rank OD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankTotal), "\n
\n "); + todaysStats.innerHTML = "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Today's stats\n
\n Points:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.points).toLocaleString(), "\n
\n Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rank), "\n
\n Villages:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.villages).toLocaleString(), "\n
\n ODA:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreAtt).toLocaleString(), "\n
\n ODA Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankAtt), "\n
\n ODD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreDef).toLocaleString(), "\n
\n ODD Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankDef), "\n
\n ODS:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreSup).toLocaleString(), "\n
\n ODS Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankSup), "\n
\n OD:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.scoreTotal).toLocaleString(), "\n
\n OD Rank:\n 0 ? statIncreaseStyle : statDecreaseStyle, "\">\n ").concat(Math.abs(stats.rankTotal), "\n
\n "); }; const renderInADayRanks = player => { @@ -675,17 +955,11 @@ const addTribeChangesListeners = () => { }; const renderTribeChanges = (e, currentPage, tribeChanges) => { - const numberOfPages = tribeChanges.total > 0 ? Math.ceil(tribeChanges.total / TRIBE_CHANGES_PER_PAGE) : 1; - const paginationItems = []; - - for (let i = 1; i <= numberOfPages; i++) { - if (i === currentPage) { - paginationItems.push(">".concat(i, "<")); - } else { - paginationItems.push("").concat(i, "")); - } - } - + const paginationItems = (0, _pagination.generatePaginationItems)({ + total: tribeChanges.total, + limit: TRIBE_CHANGES_PER_PAGE, + currentPage + }); const html = "\n
\n ").concat(paginationItems.join(''), "\n
\n \n \n \n \n \n \n \n ").concat(tribeChanges.items.map(tribeChange => { let rowHTML = '' + ""); @@ -714,7 +988,7 @@ const renderTribeChanges = (e, currentPage, tribeChanges) => { const handleShowTribeChangesButtonClick = async e => { e.preventDefault(); - const page = parseInt(e.target.getAttribute('data-page')); + const page = (0, _pagination.getPage)(e.target); if (!isNaN(page)) { const data = await (0, _requestCreator.default)({ @@ -733,33 +1007,115 @@ const handleShowTribeChangesButtonClick = async e => { } }; +const addPlayerHistoryListeners = () => { + document.querySelectorAll('#' + PLAYER_HISTORY_PAGINATION_CONTAINER_ID + ' a').forEach(el => { + el.addEventListener('click', handleShowPlayerHistoryClick); + }); +}; + +const addMathSymbol = v => { + return v > 0 ? '+' + v : v; +}; + +const renderPlayerHistory = (e, currentPage, playerHistory, playerDailyStats) => { + const paginationItems = (0, _pagination.generatePaginationItems)({ + total: playerHistory.total, + limit: PLAYER_HISTORY_PER_PAGE, + currentPage + }); + const html = "\n
\n ").concat(paginationItems.join(''), "\n
\n
\n Date\n \n New tribe\n \n Old tribe\n
".concat((0, _formatDate.default)(tribeChange.createdAt), "
\n \n \n \n \n \n \n \n \n \n \n \n \n ").concat(playerHistory.items.map(playerHistory => { + const subtracted = (0, _subDays.default)(new Date(playerHistory.createDate), 1).toISOString().split('.')[0] + 'Z'; + const stats = playerDailyStats.items.find(stats => { + return stats.createDate === subtracted; + }); + let rowHTML = '' + ""); + + if (playerHistory.tribe) { + rowHTML += ""); + } else { + rowHTML += ''; + } + + rowHTML += "\n \n \n \n \n \n \n \n ") + ''; + return rowHTML; + }).join(''), "\n \n
\n Date\n \n Tribe\n \n Rank\n \n Points\n \n Villages\n \n OD\n \n ODA\n \n ODD\n \n ODS\n
".concat((0, _formatDate.default)(playerHistory.createDate, { + year: 'numeric', + month: '2-digit', + day: '2-digit' + }), "").concat(playerHistory.tribe.tag, "-\n ".concat(playerHistory.rank, ".\n \n ").concat(playerHistory.points.toLocaleString(), "\n \n ").concat(playerHistory.totalVillages, "\n \n ").concat(playerHistory.scoreTotal.toLocaleString(), " (").concat(playerHistory.rankTotal, ")\n \n ").concat(playerHistory.scoreAtt.toLocaleString(), " (").concat(playerHistory.rankAtt, ")\n \n ").concat(playerHistory.scoreDef.toLocaleString(), " (").concat(playerHistory.rankDef, ")\n \n ").concat(playerHistory.scoreSup.toLocaleString(), " (").concat(playerHistory.rankSup, ")\n
\n "); + (0, _renderPopup.default)({ + e, + title: "Player history", + id: 'playerHistory', + html + }); + addPlayerHistoryListeners(); +}; + +const handleShowPlayerHistoryClick = async e => { + e.preventDefault(); + const page = (0, _pagination.getPage)(e.target); + + if (!isNaN(page)) { + try { + const filter = { + playerID: [PLAYER_ID], + offset: PLAYER_HISTORY_PER_PAGE * (page - 1), + limit: PLAYER_HISTORY_PER_PAGE, + sort: 'createDate DESC' + }; + const { + playerHistory, + dailyPlayerStats + } = await (0, _requestCreator.default)({ + query: PLAYER_HISTORY_AND_PLAYER_DAILY_STATS_QUERY, + variables: { + server: SERVER, + playerHistoryFilter: filter, + dailyPlayerStatsFilter: _objectSpread(_objectSpread({}, filter), {}, { + offset: filter.offset + 1 + }) + } + }); + renderPlayerHistory(e, page, playerHistory, dailyPlayerStats); + } catch (error) { + console.log('cannot load player history', error); + } + } +}; + const handleExportPlayerVillagesButtonClick = e => { e.preventDefault(); Dialog.show('Exported villages', "")); }; +const wrapAction = action => { + const actionWrapperTd = document.createElement('td'); + actionWrapperTd.colSpan = '2'; + actionWrapperTd.append(action); + const actionWrapperTr = document.createElement('tr'); + actionWrapperTr.appendChild(actionWrapperTd); + return actionWrapperTr; +}; + const renderActions = () => { const showTribeChanges = document.createElement('a'); showTribeChanges.href = '#'; - showTribeChanges.setAttribute('data-page', '1'); + (0, _pagination.setPage)(showTribeChanges, '1'); showTribeChanges.innerHTML = 'Show tribe changes'; showTribeChanges.addEventListener('click', handleShowTribeChangesButtonClick); - const showTribeChangesTd = document.createElement('td'); - showTribeChangesTd.colSpan = '2'; - showTribeChangesTd.append(showTribeChanges); - const showTribeChangesTr = document.createElement('tr'); - showTribeChangesTr.appendChild(showTribeChangesTd); - actionsContainer.appendChild(showTribeChangesTr); + actionsContainer.appendChild(wrapAction(showTribeChanges)); + const showPlayerHistory = document.createElement('a'); + showPlayerHistory.href = '#'; + (0, _pagination.setPage)(showPlayerHistory, '1'); + showPlayerHistory.innerHTML = 'Show player history'; + showPlayerHistory.addEventListener('click', handleShowPlayerHistoryClick); + actionsContainer.appendChild(wrapAction(showPlayerHistory)); const exportPlayerVillages = document.createElement('a'); exportPlayerVillages.href = '#'; exportPlayerVillages.innerHTML = "Export player's villages"; exportPlayerVillages.addEventListener('click', handleExportPlayerVillagesButtonClick); - const exportPlayerVillagesTd = document.createElement('td'); - exportPlayerVillagesTd.colSpan = '2'; - exportPlayerVillagesTd.append(exportPlayerVillages); - const exportPlayerVillagesTr = document.createElement('tr'); - exportPlayerVillagesTr.appendChild(exportPlayerVillagesTd); - actionsContainer.appendChild(exportPlayerVillagesTr); + actionsContainer.appendChild(wrapAction(exportPlayerVillages)); }; (async function () { @@ -780,4 +1136,4 @@ const renderActions = () => { console.log('extended player profile', error); } })(); -},{"./libs/requestCreator":"Ph2E","./utils/getIDFromURL":"tQUs","./utils/getCurrentServer":"DMkL","./utils/formatDate":"V6Mf","./utils/renderPopup":"P4rL","./utils/twstats":"Syko","./utils/tribalwars":"fHHP","./utils/localStorage":"KWxH"}]},{},["yRop"], null) \ No newline at end of file +},{"date-fns/subDays":"mRRL","./libs/requestCreator":"Ph2E","./libs/pagination":"m41w","./utils/getIDFromURL":"tQUs","./utils/getCurrentServer":"DMkL","./utils/formatDate":"V6Mf","./utils/renderPopup":"P4rL","./utils/twstats":"Syko","./utils/tribalwars":"fHHP","./utils/localStorage":"KWxH"}]},{},["yRop"], null) \ No newline at end of file diff --git a/src/extendedPlayerProfile.js b/src/extendedPlayerProfile.js index 8b9c0a3..24183d3 100644 --- a/src/extendedPlayerProfile.js +++ b/src/extendedPlayerProfile.js @@ -1,4 +1,6 @@ +import subDays from 'date-fns/subDays'; import requestCreator from './libs/requestCreator'; +import { generatePaginationItems, setPage, getPage } from './utils/pagination'; import getIDFromURL from './utils/getIDFromURL'; import getCurrentServer from './utils/getCurrentServer'; import formatDate from './utils/formatDate'; @@ -12,7 +14,7 @@ import { setItem, getItem } from './utils/localStorage'; // @namespace https://github.com/tribalwarshelp/scripts // @updateURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/extendedPlayerProfile.js // @downloadURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/extendedPlayerProfile.js -// @version 0.5 +// @version 0.6 // @description Extended Player Profile // @author Kichiyaki http://dawid-wysokinski.pl/ // @match *://*.plemiona.pl/game.php*&screen=info_player* @@ -86,6 +88,48 @@ const TRIBE_CHANGES_QUERY = ` `; const TRIBE_CHANGES_PAGINATION_CONTAINER_ID = 'tribeChangesPagination'; const TRIBE_CHANGES_PER_PAGE = 15; +const PLAYER_HISTORY_AND_PLAYER_DAILY_STATS_QUERY = ` +query playerHistoryAndPlayerDailyStats($server: String!, + $playerHistoryFilter: PlayerHistoryFilter!, + $dailyPlayerStatsFilter: DailyPlayerStatsFilter!) { + playerHistory(server: $server, filter: $playerHistoryFilter) { + total + items { + totalVillages + points + rank + scoreAtt + rankAtt + scoreDef + rankDef + scoreSup + rankSup + scoreTotal + rankTotal + tribe { + id + tag + } + createDate + } + } + dailyPlayerStats(server: $server, filter: $dailyPlayerStatsFilter) { + items { + points + scoreAtt + scoreAtt + scoreDef + scoreSup + scoreTotal + villages + createDate + } + } +} +`; +const PLAYER_HISTORY_PAGINATION_CONTAINER_ID = 'playerHistoryPagination'; +const PLAYER_HISTORY_PER_PAGE = 15; + const profileInfoTBody = document.querySelector('#player_info > tbody'); const actionsContainer = PLAYER_ID === CURRENT_PLAYER_ID @@ -312,7 +356,7 @@ const renderTodaysStats = (stats) => { - Rank ODA: + ODA Rank: 0 ? statIncreaseStyle : statDecreaseStyle @@ -352,7 +396,7 @@ const renderTodaysStats = (stats) => { - Rank ODS: + ODS Rank: 0 ? statIncreaseStyle : statDecreaseStyle @@ -530,20 +574,11 @@ const addTribeChangesListeners = () => { }; const renderTribeChanges = (e, currentPage, tribeChanges) => { - const numberOfPages = - tribeChanges.total > 0 - ? Math.ceil(tribeChanges.total / TRIBE_CHANGES_PER_PAGE) - : 1; - const paginationItems = []; - for (let i = 1; i <= numberOfPages; i++) { - if (i === currentPage) { - paginationItems.push(`>${i}<`); - } else { - paginationItems.push( - `${i}` - ); - } - } + const paginationItems = generatePaginationItems({ + total: tribeChanges.total, + limit: TRIBE_CHANGES_PER_PAGE, + currentPage, + }); const html = `
${paginationItems.join('')} @@ -598,7 +633,7 @@ const renderTribeChanges = (e, currentPage, tribeChanges) => { const handleShowTribeChangesButtonClick = async (e) => { e.preventDefault(); - const page = parseInt(e.target.getAttribute('data-page')); + const page = getPage(e.target); if (!isNaN(page)) { const data = await requestCreator({ query: TRIBE_CHANGES_QUERY, @@ -616,6 +651,167 @@ const handleShowTribeChangesButtonClick = async (e) => { } }; +const addPlayerHistoryListeners = () => { + document + .querySelectorAll('#' + PLAYER_HISTORY_PAGINATION_CONTAINER_ID + ' a') + .forEach((el) => { + el.addEventListener('click', handleShowPlayerHistoryClick); + }); +}; + +const addMathSymbol = (v) => { + return v > 0 ? '+' + v : v; +}; + +const renderPlayerHistory = ( + e, + currentPage, + playerHistory, + playerDailyStats +) => { + const paginationItems = generatePaginationItems({ + total: playerHistory.total, + limit: PLAYER_HISTORY_PER_PAGE, + currentPage, + }); + const html = ` +
+ ${paginationItems.join('')} +
+ + + + + + + + + + + + + + ${playerHistory.items + .map((playerHistory) => { + const subtracted = + subDays(new Date(playerHistory.createDate), 1) + .toISOString() + .split('.')[0] + 'Z'; + const stats = playerDailyStats.items.find((stats) => { + return stats.createDate === subtracted; + }); + + let rowHTML = + '' + + ``; + if (playerHistory.tribe) { + rowHTML += ``; + } else { + rowHTML += ''; + } + rowHTML += + ` + + + + + + + + ` + ''; + + return rowHTML; + }) + .join('')} + +
+ Date + + Tribe + + Rank + + Points + + Villages + + OD + + ODA + + ODD + + ODS +
${formatDate(playerHistory.createDate, { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })}${playerHistory.tribe.tag}- + ${playerHistory.rank}. + + ${playerHistory.points.toLocaleString()} + + ${playerHistory.totalVillages} + + ${playerHistory.scoreTotal.toLocaleString()} (${ + playerHistory.rankTotal + }) + + ${playerHistory.scoreAtt.toLocaleString()} (${ + playerHistory.rankAtt + }) + + ${playerHistory.scoreDef.toLocaleString()} (${ + playerHistory.rankDef + }) + + ${playerHistory.scoreSup.toLocaleString()} (${ + playerHistory.rankSup + }) +
+ `; + + renderPopup({ + e, + title: `Player history`, + id: 'playerHistory', + html, + }); + + addPlayerHistoryListeners(); +}; + +const handleShowPlayerHistoryClick = async (e) => { + e.preventDefault(); + const page = getPage(e.target); + if (!isNaN(page)) { + try { + const filter = { + playerID: [PLAYER_ID], + offset: PLAYER_HISTORY_PER_PAGE * (page - 1), + limit: PLAYER_HISTORY_PER_PAGE, + sort: 'createDate DESC', + }; + const { playerHistory, dailyPlayerStats } = await requestCreator({ + query: PLAYER_HISTORY_AND_PLAYER_DAILY_STATS_QUERY, + variables: { + server: SERVER, + playerHistoryFilter: filter, + dailyPlayerStatsFilter: { + ...filter, + offset: filter.offset + 1, + }, + }, + }); + renderPlayerHistory(e, page, playerHistory, dailyPlayerStats); + } catch (error) { + console.log('cannot load player history', error); + } + } +}; + const handleExportPlayerVillagesButtonClick = (e) => { e.preventDefault(); @@ -628,18 +824,29 @@ const handleExportPlayerVillagesButtonClick = (e) => { ); }; +const wrapAction = (action) => { + const actionWrapperTd = document.createElement('td'); + actionWrapperTd.colSpan = '2'; + actionWrapperTd.append(action); + const actionWrapperTr = document.createElement('tr'); + actionWrapperTr.appendChild(actionWrapperTd); + return actionWrapperTr; +}; + const renderActions = () => { const showTribeChanges = document.createElement('a'); showTribeChanges.href = '#'; - showTribeChanges.setAttribute('data-page', '1'); + setPage(showTribeChanges, '1'); showTribeChanges.innerHTML = 'Show tribe changes'; showTribeChanges.addEventListener('click', handleShowTribeChangesButtonClick); - const showTribeChangesTd = document.createElement('td'); - showTribeChangesTd.colSpan = '2'; - showTribeChangesTd.append(showTribeChanges); - const showTribeChangesTr = document.createElement('tr'); - showTribeChangesTr.appendChild(showTribeChangesTd); - actionsContainer.appendChild(showTribeChangesTr); + actionsContainer.appendChild(wrapAction(showTribeChanges)); + + const showPlayerHistory = document.createElement('a'); + showPlayerHistory.href = '#'; + setPage(showPlayerHistory, '1'); + showPlayerHistory.innerHTML = 'Show player history'; + showPlayerHistory.addEventListener('click', handleShowPlayerHistoryClick); + actionsContainer.appendChild(wrapAction(showPlayerHistory)); const exportPlayerVillages = document.createElement('a'); exportPlayerVillages.href = '#'; @@ -648,21 +855,18 @@ const renderActions = () => { 'click', handleExportPlayerVillagesButtonClick ); - const exportPlayerVillagesTd = document.createElement('td'); - exportPlayerVillagesTd.colSpan = '2'; - exportPlayerVillagesTd.append(exportPlayerVillages); - const exportPlayerVillagesTr = document.createElement('tr'); - exportPlayerVillagesTr.appendChild(exportPlayerVillagesTd); - actionsContainer.appendChild(exportPlayerVillagesTr); + actionsContainer.appendChild(wrapAction(exportPlayerVillages)); }; (async function () { try { renderActions(); + const dataFromCache = loadDataFromCache(); if (dataFromCache && dataFromCache.player) { render(dataFromCache); } + const dataFromAPI = await loadData(); if (dataFromAPI) { render(dataFromAPI); diff --git a/src/utils/pagination.js b/src/utils/pagination.js new file mode 100644 index 0000000..9908f31 --- /dev/null +++ b/src/utils/pagination.js @@ -0,0 +1,51 @@ +const ATTRIBUTE = 'data-page'; + +export const setPage = (el, page = 1) => { + if (!el instanceof HTMLElement) { + throw new Error('Expected HTMLElement as the first argument'); + } + page = parseInt(page); + if (typeof page !== 'number' || isNaN(page)) { + throw new Error('Expected number or string as the second argument'); + } + el.setAttribute(ATTRIBUTE, page + ''); +}; + +export const getPage = (el) => { + if (!el instanceof HTMLElement) { + return 0; + } + return parseInt(el.getAttribute(ATTRIBUTE)); +}; + +export const calcNumberOfPages = (total, limit) => { + if (typeof total !== 'number') { + throw new Error('Expected number as the first argument'); + } + if (typeof limit !== 'number') { + throw new Error('Expected number as the second argument'); + } + return total > 0 ? Math.ceil(total / limit) : 1; +}; + +export const generatePaginationItems = ({ + total, + limit, + marginRight = 3, + currentPage = 0, +} = {}) => { + const numberOfPages = calcNumberOfPages(total, limit); + const paginationItems = []; + for (let i = 1; i <= numberOfPages; i++) { + if (i === currentPage) { + paginationItems.push( + `>${i}<` + ); + } else { + paginationItems.push( + `${i}` + ); + } + } + return paginationItems; +};