- // ==UserScript==
- // @name Hordes UI Mod
- // @version 1.0.2
- // @description Various UI mods for Hordes.io.
- // @author Sakaiyo & Chandog#6373 & Cullen
- // @match https://hordes.io/play
- // @grant GM_addStyle
- // @namespace https://greasyfork.org/users/160017
- // ==/UserScript==
-
- GM_addStyle(`/* Custom css for settings page, duplicates preexisting settings pane grid */
- .uimod-settings {
- display: grid;
- grid-template-columns: 2fr 3fr;
- grid-gap: 8px;
- align-items: center;
- max-height: 390px;
- margin: 0 20px;
- overflow-y: auto; }
- /* Custom chat context menu, invisible by default */
- .js-chat-context-menu {
- display: none; }
-
- .js-chat-context-menu .name {
- color: white;
- padding: 2px 4px; }
-
- /* Allow names in chat to be clicked (textf1 = BL, textf0 = VG) */
- #chat .name,
- .textwhisper .textf1,
- .textwhisper .textf0 {
- pointer-events: all !important; }
- /* Custom chat filter colors */
- .js-chat-gm {
- color: #a6dcd5; }
-
- /* Class that hides chat lines */
- .js-line-hidden,
- .js-line-blocked {
- display: none; }
- /* Custom chat tabs */
- .uimod-chat-tabs {
- position: fixed;
- margin-top: -22px;
- left: 5px;
- pointer-events: all;
- color: #5b858e;
- font-size: 12px;
- font-weight: bold; }
-
- .uimod-chat-tabs > div {
- cursor: pointer;
- background-color: rgba(0, 0, 0, 0.4);
- border-top-right-radius: 4px;
- border-top-left-radius: 4px;
- display: inline-block;
- border: 1px black solid;
- border-bottom: 0;
- margin-right: 2px;
- padding: 3px 5px; }
-
- .uimod-chat-tabs > div:not(.js-selected-tab):hover {
- border-color: #aaa; }
-
- .uimod-chat-tabs > .js-selected-tab {
- color: #fff; }
-
- /* Chat tab custom config */
- .uimod-chat-tab-config {
- position: absolute;
- z-index: 9999999;
- background-color: rgba(0, 0, 0, 0.6);
- color: white;
- border-radius: 3px;
- text-align: center;
- padding: 8px 12px 8px 6px;
- width: 175px;
- font-size: 14px;
- border: 1px solid black;
- display: none; }
-
- .uimod-chat-tab-config-grid {
- grid-template-columns: 35% 65%;
- display: grid;
- grid-gap: 6px;
- align-items: center; }
-
- .uimod-chat-tab-config h1 {
- font-size: 16px;
- margin-top: 0; }
-
- .uimod-chat-tab-config .btn,
- .uimod-chat-tab-config input {
- font-size: 12px; }
- /* Allows windows to be moved */
- .window {
- position: relative; }
-
- /* All purpose hidden class */
- .js-hidden {
- display: none; }
- /* Friends list CSS, similar to settings but supports 4 columns */
- .uimod-friends {
- display: grid;
- grid-template-columns: 2fr 1.1fr 1.5fr 0.33fr 3fr;
- grid-gap: 8px;
- align-items: center;
- max-height: 390px;
- margin: 0 20px;
- overflow-y: auto; }
- .js-map-btns {
- position: absolute;
- top: 46px;
- right: 12px;
- z-index: 999;
- width: 100px;
- height: 100px;
- text-align: right;
- display: none;
- pointer-events: all; }
-
- .js-map-btns:hover {
- display: block; }
-
- .js-map-btns button {
- border-radius: 10px;
- font-size: 18px;
- padding: 0 5px;
- background: rgba(0, 0, 0, 0.4);
- border: 0;
- color: white;
- font-weight: bold;
- cursor: pointer; }
-
- /* On hover of map, show opacity controls */
- .js-map:hover .js-map-btns {
- display: block; }
- .js-chat-resize {
- resize: both;
- overflow: auto; }
- .js-map {
- /* This makes sure scroll bars don't appear when resizing the map */
- overflow: hidden; }
-
- .js-map-resize:hover {
- resize: both;
- overflow: auto;
- direction: rtl; }
- /* Allows last clicked window to appear above all other windows */
- .js-is-top {
- z-index: 9998 !important; }
-
- .panel.context:not(.commandlist) {
- z-index: 9999 !important; }
-
- /* The item icon being dragged in the inventory */
- .container.svelte-120o2pb {
- z-index: 9999 !important; }
- .container.uimod-xpmeter-1 {
- z-index: 6; }
-
- .window.uimod-xpmeter-2 {
- padding: 5px;
- height: 100%;
- display: grid;
- grid-template-rows: 30px 1fr;
- grid-gap: 4px;
- transform-origin: inherit;
- min-width: fit-content; }
-
- .titleframe.uimod-xpmeter-2 {
- line-height: 1em;
- display: flex;
- align-items: center;
- position: relative;
- letter-spacing: 0.5px; }
-
- .titleicon.uimod-xpmeter-2 {
- margin: 3px; }
-
- .title.uimod-xpmeter-2 {
- width: 100%;
- padding-left: 4px;
- font-weight: bold; }
-
- .slot.uimod-xpmeter-2 {
- min-height: 0; }
-
- .wrapper.uimod-xpmeter-1 {
- width: 200px; }
-
- .bar.uimod-xpmeter-3 {
- background-color: rgba(45, 66, 71, 0.7);
- border-radius: 1.5px;
- position: relative;
- color: #DAE8EA;
- overflow: hidden;
- text-shadow: 1px 1px 2px #10131d;
- white-space: nowrap;
- text-transform: capitalize;
- font-weight: bold; }
-
- .buttons.uimod-xpmeter-1 {
- line-height: 1;
- font-size: 13px; }
-
- .left.uimod-xpmeter-3 {
- padding-left: 4px;
- position: relative;
- z-index: 1; }
-
- .right.uimod-xpmeter-3 {
- position: absolute;
- right: 7px;
- z-index: 1; }
- /* This file is for CSS mods that don't fit in any other individual mod folder */
- /* Transparent chat bg color */
- .frame.svelte-1vrlsr3 {
- background: rgba(0, 0, 0, 0.4); }
-
- /* Our mod's chat message color */
- .textuimod {
- color: #00dd33; }
-
- /* The browser resize icon */
- *::-webkit-resizer {
- background: linear-gradient(to right, rgba(51, 77, 80, 0), rgba(203, 202, 165, 0.5));
- border-radius: 8px;
- box-shadow: 0 1px 1px black; }
-
- *::-moz-resizer {
- background: linear-gradient(to right, rgba(51, 77, 80, 0), rgba(203, 202, 165, 0.5));
- border-radius: 8px;
- box-shadow: 0 1px 1px black; }
-
- /* Our custom window, closely mirrors main settings window */
- .uimod-custom-window {
- position: absolute;
- top: 100px;
- left: 50%;
- transform: translate(-50%, 0);
- min-width: 350px;
- max-width: 600px;
- width: 90%;
- height: 80%;
- min-height: 350px;
- max-height: 500px;
- z-index: 9;
- padding: 0px 10px 5px; }
- `);
-
- (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
- "use strict";
-
- var _mods = _interopRequireDefault(require("./mods"));
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- // Add new DOM, load our stored state, wire it up, then continuously rerun specific methods whenever UI changes
- function initialize() {
- // If the Hordes.io tab isn't active for long enough, it reloads the entire page, clearing this mod
- // We check for that and reinitialize the mod if that happens
- const $layout = document.querySelector('.layout');
-
- if ($layout.classList.contains('uimod-initd')) {
- return;
- }
-
- $layout.classList.add('uimod-initd');
- const rerunning = {
- // MutationObserver running whenever .layout changes
- onDomChange: [],
- // Mutation observer running whenever #chat changes
- onChatChange: [],
- // `click` Event listener running on document.body
- onPageClick: []
- }; // Run all our mods
-
- const registerOnDomChange = callback => rerunning.onDomChange.push(callback);
-
- const registerOnChatChange = callback => rerunning.onChatChange.push(callback);
-
- const registerOnPageClick = callback => rerunning.onPageClick.push(callback);
-
- _mods.default.forEach(mod => {
- mod.run({
- registerOnDomChange,
- registerOnChatChange,
- registerOnPageClick
- });
- }); // Continuously re-run specific mods methods that need to be executed on UI change
-
-
- const rerunObserver = new MutationObserver(() => {
- // If new window appears, e.g. even if window is closed and reopened, we need to rewire it
- // Fun fact: Some windows always exist in the DOM, even when hidden, e.g. Inventory
- // But some windows only exist in the DOM when open, e.g. Interaction
- rerunning.onDomChange.forEach(callback => callback());
- });
- rerunObserver.observe(document.querySelector('.layout > .container'), {
- attributes: false,
- childList: true
- }); // Rerun only on chat messages changing
-
- const chatRerunObserver = new MutationObserver(() => {
- rerunning.onChatChange.forEach(callback => callback());
- });
- chatRerunObserver.observe(document.querySelector('#chat'), {
- attributes: false,
- childList: true
- }); // Event listeners for document.body might be kept when the game reloads, so don't reinitialize them
-
- if (!document.body.classList.contains('js-uimod-initd')) {
- document.body.classList.add('js-uimod-initd');
- rerunning.onPageClick.forEach(callback => document.body.addEventListener('click', callback));
- }
- } // Initialize mods once UI DOM has loaded
-
-
- const pageObserver = new MutationObserver(() => {
- const isUiLoaded = !!document.querySelector('.layout');
-
- if (isUiLoaded) {
- initialize();
- }
- });
- pageObserver.observe(document.body, {
- attributes: true,
- childList: true
- });
-
- },{"./mods":12}],2:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var chat = _interopRequireWildcard(require("../../utils/chat"));
-
- var _version = require("../../utils/version");
-
- var _state = require("../../utils/state");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- function modStart() {
- chat.addChatMessage(`Hordes UI Mod v${_version.VERSION} is now running.`);
- (0, _state.loadState)();
- }
-
- var _default = {
- name: '[REQUIRED] UI Mod Startup',
- description: 'Do not remove this! This handles some initial mod loading, including loading saved state.',
- run: modStart
- };
- exports.default = _default;
-
- },{"../../utils/chat":21,"../../utils/state":24,"../../utils/version":25}],3:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var _misc = require("../../utils/misc");
-
- var player = _interopRequireWildcard(require("../../utils/player"));
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- function blockedPlayerSettings() {
- const state = (0, _state.getState)();
- const $settings = document.querySelector('.divide:not(.js-settings-initd)');
-
- if (!$settings) {
- return;
- }
-
- $settings.classList.add('js-settings-initd');
- const $settingsChoiceList = $settings.querySelector('.choice').parentNode;
- $settingsChoiceList.appendChild((0, _misc.makeElement)({
- element: 'div',
- class: 'choice js-blocked-players',
- content: 'Blocked players'
- })); // Upon click, we display our custom settings window UI
-
- document.querySelector('.js-blocked-players').addEventListener('click', () => {
- let blockedPlayersHTML = '';
- Object.keys(state.blockList).sort().forEach(blockedName => {
- blockedPlayersHTML += `
- <div data-player-name="${blockedName}">${blockedName}</div>
- <div class="btn orange js-unblock-player" data-player-name="${blockedName}">Unblock player</div>
- `;
- });
- const customSettingsHTML = `
- <h3 class="textprimary">Blocked players</h3>
- <div class="settings uimod-settings">${blockedPlayersHTML}</div>
- <p></p>
- <div class="btn purp js-close-custom-settings">Close</div>
- `;
- const $customSettings = (0, _misc.makeElement)({
- element: 'div',
- class: 'menu panel-black js-custom-settings uimod-custom-window',
- content: customSettingsHTML
- });
- document.body.appendChild($customSettings); // Wire up all the unblock buttons
-
- Array.from(document.querySelectorAll('.js-unblock-player')).forEach($button => {
- $button.addEventListener('click', clickEvent => {
- const name = clickEvent.target.getAttribute('data-player-name');
- player.unblockPlayer(name); // Remove the blocked player from the list
-
- Array.from(document.querySelectorAll(`.js-custom-settings [data-player-name="${name}"]`)).forEach($element => {
- $element.parentNode.removeChild($element);
- });
- });
- }); // And the close button for our custom UI
-
- document.querySelector('.js-close-custom-settings').addEventListener('click', () => {
- const $customSettingsWindow = document.querySelector('.js-custom-settings');
- $customSettingsWindow.parentNode.removeChild($customSettingsWindow);
- });
- });
- }
-
- var _default = {
- name: 'Blocked Players List',
- description: 'Allows you to view and remove blocked players from the Settings window',
- run: ({
- registerOnDomChange
- }) => {
- blockedPlayerSettings(); // If the settings window becomes visible/invisible, we want to update it
-
- registerOnDomChange(blockedPlayerSettings);
- }
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/player":23,"../../utils/state":24}],4:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.showChatContextMenu = showChatContextMenu;
-
- var _state = require("../../utils/state");
-
- // Makes chat context menu visible and appear under the mouse
- function showChatContextMenu(name, mousePos) {
- const state = (0, _state.getState)(); // Right before we show the context menu, we want to handle showing/hiding Friend/Unfriend
-
- const $contextMenu = document.querySelector('.js-chat-context-menu');
- $contextMenu.querySelector('[name="friend"]').classList.toggle('js-hidden', !!state.friendsList[name]);
- $contextMenu.querySelector('[name="unfriend"]').classList.toggle('js-hidden', !state.friendsList[name]);
- $contextMenu.querySelector('.js-name').textContent = name;
- $contextMenu.setAttribute('style', `display: block; left: ${mousePos.x}px; top: ${mousePos.y}px;`);
- }
-
- },{"../../utils/state":24}],5:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var _misc = require("../../utils/misc");
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var chat = _interopRequireWildcard(require("../../utils/chat"));
-
- var player = _interopRequireWildcard(require("../../utils/player"));
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // This creates the initial chat context menu DOM (which starts as hidden)
- function createChatContextMenu() {
- const tempState = (0, _state.getTempState)();
-
- if (document.querySelector('.js-chat-context-menu')) {
- return;
- }
-
- let contextMenuHTML = `
- <div class="js-name">...</div>
- <div class="choice" name="party">Party invite</div>
- <div class="choice" name="whisper">Whisper</div>
- <div class="choice" name="friend">Friend</div>
- <div class="choice" name="unfriend">Unfriend</div>
- <div class="choice" name="copy">Copy name</div>
- <div class="choice" name="block">Block</div>
- `;
- document.body.appendChild((0, _misc.makeElement)({
- element: 'div',
- class: 'panel context border grey js-chat-context-menu',
- content: contextMenuHTML
- }));
- const $chatContextMenu = document.querySelector('.js-chat-context-menu');
- $chatContextMenu.querySelector('[name="party"]').addEventListener('click', () => {
- chat.partyPlayer(tempState.chatName);
- });
- $chatContextMenu.querySelector('[name="whisper"]').addEventListener('click', () => {
- chat.whisperPlayer(tempState.chatName);
- });
- $chatContextMenu.querySelector('[name="friend"]').addEventListener('click', () => {
- player.friendPlayer(tempState.chatName);
- });
- $chatContextMenu.querySelector('[name="unfriend"]').addEventListener('click', () => {
- player.unfriendPlayer(tempState.chatName);
- });
- $chatContextMenu.querySelector('[name="copy"]').addEventListener('click', () => {
- navigator.clipboard.writeText(tempState.chatName);
- });
- $chatContextMenu.querySelector('[name="block"]').addEventListener('click', () => {
- player.blockPlayer(tempState.chatName);
- });
- } // This opens a context menu when you click a user's name in chat
-
-
- function chatContextMenu() {
- const tempState = (0, _state.getTempState)();
-
- const addContextMenu = ($name, name) => {
- $name.classList.add('js-is-context-menu-initd'); // Add name to element so we can target it in CSS when filtering chat for block list
-
- $name.setAttribute('data-chat-name', name);
-
- const showContextMenu = clickEvent => {
- // TODO: Is there a way to pass the name to showChatContextMenumethod, instead of storing in tempState?
- tempState.chatName = name;
- helpers.showChatContextMenu(name, {
- x: clickEvent.pageX,
- y: clickEvent.pageY
- });
- };
-
- $name.addEventListener('click', showContextMenu); // Left click
-
- $name.addEventListener('contextmenu', showContextMenu); // Right click works too
- };
-
- Array.from(document.querySelectorAll('#chat .name:not(.js-is-context-menu-initd)')).forEach($name => {
- addContextMenu($name, $name.textContent);
- }); // `textf0` is the VG faction, `textf1` is the BL faction - we want to support both with our whisper context menu
-
- Array.from(document.querySelectorAll('.textwhisper .textf1:not(.js-is-context-menu-initd), .textwhisper .textf0:not(.js-is-context-menu-initd)')).forEach($whisperName => {
- // $whisperName's textContent is "to [name]" or "from [name]", so we cut off the first word
- let name = $whisperName.textContent.split(' ');
- name.shift(); // Remove the first word
-
- name = name.join(' ');
- addContextMenu($whisperName, name);
- });
- } // Close chat context menu if clicking outside of it
-
-
- function closeChatContextMenu(clickEvent) {
- const $target = clickEvent.target; // If clicking on name or directly on context menu, don't close it
- // Still closes if clicking on context menu item
-
- if ($target.classList.contains('js-is-context-menu-initd') || $target.classList.contains('js-chat-context-menu')) {
- return;
- }
-
- const $contextMenu = document.querySelector('.js-chat-context-menu');
- $contextMenu.style.display = 'none';
- }
-
- var _default = {
- name: 'Chat Context Menu',
- description: 'Displays a menu when you click on a player, allowing you to whisper/party/friend/block them',
- run: ({
- registerOnPageClick,
- registerOnChatChange
- }) => {
- createChatContextMenu();
- chatContextMenu(); // When we click anywhere on the page outside of our chat context menu, we want to close the menu
-
- registerOnPageClick(closeChatContextMenu); // Register event listeners for each name when a new chat message appears
-
- registerOnChatChange(chatContextMenu);
- }
- };
- exports.default = _default;
-
- },{"../../utils/chat":21,"../../utils/misc":22,"../../utils/player":23,"../../utils/state":24,"./helpers":4}],6:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var chat = _interopRequireWildcard(require("../../utils/chat"));
-
- var _state = require("../../utils/state");
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // Creates DOM elements for custom chat filters
- function newChatFilters() {
- const state = (0, _state.getState)();
- const $channelselect = document.querySelector('.channelselect');
-
- if (!document.querySelector(`.js-chat-gm`)) {
- const $gm = (0, _misc.makeElement)({
- element: 'small',
- class: `btn border black js-chat-gm ${state.chat.GM ? '' : 'textgrey'}`,
- content: 'GM'
- });
- $channelselect.appendChild($gm);
- }
- } // Wire up new chat buttons to toggle in state+ui
-
-
- function newChatFilterButtons() {
- const state = (0, _state.getState)();
- const $chatGM = document.querySelector(`.js-chat-gm`);
- $chatGM.addEventListener('click', () => {
- chat.setGMChatVisibility(!state.chat.GM);
- });
- }
-
- var _default = {
- name: 'Chat filters',
- description: 'Enables custom chat filters: GM chat',
- run: ({
- registerOnChatChange
- }) => {
- newChatFilters();
- newChatFilterButtons(); // Whenever chat changes, we want to filter it
-
- registerOnChatChange(chat.filterAllChat);
- }
- };
- exports.default = _default;
-
- },{"../../utils/chat":21,"../../utils/misc":22,"../../utils/state":24}],7:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.showChatTabConfigWindow = showChatTabConfigWindow;
- exports.addChatTab = addChatTab;
- exports.selectChatTab = selectChatTab;
- exports.getCurrentChatFilters = getCurrentChatFilters;
-
- var chat = _interopRequireWildcard(require("../../utils/chat"));
-
- var _state = require("../../utils/state");
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- const DEFAULT_CHAT_TAB_NAME = 'Untitled'; // Gets current chat filters as represented in the UI
- // filter being true means it's invisible(filtered) in chat
- // filter being false means it's visible(unfiltered) in chat
-
- function getCurrentChatFilters() {
- const state = (0, _state.getState)(); // Saved by the official game client
-
- const gameFilters = JSON.parse(localStorage.getItem('filteredChannels'));
- return {
- global: gameFilters.includes('global'),
- faction: gameFilters.includes('faction'),
- party: gameFilters.includes('party'),
- clan: gameFilters.includes('clan'),
- pvp: gameFilters.includes('pvp'),
- inv: gameFilters.includes('inv'),
- GM: !state.chat.GM // state.chat.GM is whether or not GM chat is shown - we want whether or not GM chat should be hidden
-
- };
- } // Shows the chat tab config window for a specific tab, displayed in a specific position
-
-
- function showChatTabConfigWindow(tabId, pos) {
- const state = (0, _state.getState)();
- const tempState = getTempState();
- const $chatTabConfig = document.querySelector('.js-chat-tab-config');
- const chatTab = state.chatTabs.find(tab => tab.id === tabId); // Update position and name in chat tab config
-
- $chatTabConfig.style.left = `${pos.x}px`;
- $chatTabConfig.style.top = `${pos.y}px`;
- $chatTabConfig.querySelector('.js-chat-tab-name').value = chatTab.name; // Store tabId in state, to be used by the Remove/Add buttons in config window
-
- tempState.editedChatTabId = tabId; // Hide remove button if only one chat tab left - can't remove last one
- // Show it if more than one chat tab left
-
- const chatTabCount = Object.keys(state.chatTabs).length;
- const $removeChatTabBtn = $chatTabConfig.querySelector('.js-remove-chat-tab');
- $removeChatTabBtn.style.display = chatTabCount < 2 ? 'none' : 'block'; // Show chat tab config
-
- $chatTabConfig.style.display = 'block';
- } // Adds chat tab to DOM, sets it as selected
- // If argument chatTab is provided, will use that name+id
- // If no argument is provided, will create new tab name/id and add it to state
- // isInittingTab is optional boolean, if `true`, will _not_ set added tab as selected. Used when initializing all chat tabs on load
- // Returns newly added tabId
-
-
- function addChatTab(chatTab, isInittingTab) {
- const state = (0, _state.getState)();
- let tabName = DEFAULT_CHAT_TAB_NAME;
- let tabId = (0, _misc.uuid)();
-
- if (chatTab) {
- tabName = chatTab.name;
- tabId = chatTab.id;
- } else {
- // If no chat tab was provided, create it in state
- state.chatTabs.push({
- name: tabName,
- id: tabId,
- filters: getCurrentChatFilters()
- });
- (0, _state.saveState)();
- }
-
- const $tabs = document.querySelector('.js-chat-tabs');
- const $tab = (0, _misc.makeElement)({
- element: 'div',
- content: tabName
- });
- $tab.setAttribute('data-tab-id', tabId); // Add chat tab to DOM
-
- $tabs.appendChild($tab); // Wire chat tab up to open config on right click
-
- $tab.addEventListener('contextmenu', clickEvent => {
- const mousePos = {
- x: clickEvent.pageX,
- y: clickEvent.pageY
- };
- showChatTabConfigWindow(tabId, mousePos);
- }); // And select chat tab on left click
-
- $tab.addEventListener('click', () => {
- selectChatTab(tabId);
- });
-
- if (!isInittingTab) {
- // Select the newly added chat tab
- selectChatTab(tabId);
- } // Returning tabId to all adding new tab to pass tab ID to `showChatTabConfigWindow`
-
-
- return tabId;
- } // Selects chat tab [on click], updating client chat filters and custom chat filters
-
-
- function selectChatTab(tabId) {
- const state = (0, _state.getState)(); // Remove selected class from everything, then add selected class to clicked tab
-
- Array.from(document.querySelectorAll('[data-tab-id]')).forEach($tab => {
- $tab.classList.remove('js-selected-tab');
- });
- const $tab = document.querySelector(`[data-tab-id="${tabId}"]`);
- $tab.classList.add('js-selected-tab');
- const tabFilters = state.chatTabs.find(tab => tab.id === tabId).filters; // Simulating clicks on the filters to turn them on/off
-
- const $filterButtons = Array.from(document.querySelectorAll('.channelselect small'));
- Object.keys(tabFilters).forEach(filter => {
- const $filterButton = $filterButtons.find($btn => $btn.textContent === filter);
- const isCurrentlyFiltered = $filterButton.classList.contains('textgrey'); // If is currently filtered but filter for this tab is turned off, click it to turn filter off
-
- if (isCurrentlyFiltered && !tabFilters[filter]) {
- $filterButton.click();
- } // If it is not currently filtered but filter for this tab is turned on, click it to turn filter on
-
-
- if (!isCurrentlyFiltered && tabFilters[filter]) {
- $filterButton.click();
- }
- }); // Update state for our custom chat filters to match the tab's configuration, then filter chat for it
-
- const isGMChatVisible = !tabFilters.GM;
- chat.setGMChatVisibility(isGMChatVisible); // Update the selected tab in state
-
- state.selectedChatTabId = tabId;
- (0, _state.saveState)();
- }
-
- },{"../../utils/chat":21,"../../utils/misc":22,"../../utils/state":24}],8:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var _state = require("../../utils/state");
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // Creates DOM elements and wires them up for custom chat tabs and chat tab config
- // Note: Should be done after creating new custom chat filters
- function customChatTabs() {
- const state = (0, _state.getState)();
- const tempState = (0, _state.getTempState)(); // Create the chat tab configuration DOM
-
- const $chatTabConfigurator = (0, _misc.makeElement)({
- element: 'div',
- class: 'uimod-chat-tab-config js-chat-tab-config',
- content: `
- <h1>Chat Tab Config</h1>
- <div class="uimod-chat-tab-config-grid">
- <div>Name</div><input type="text" class="js-chat-tab-name" value="untitled"></input>
- <div class="btn orange js-remove-chat-tab">Remove</div><div class="btn blue js-save-chat-tab">Ok</div>
- </div>
- `
- });
- document.body.append($chatTabConfigurator); // Wire it up
-
- document.querySelector('.js-remove-chat-tab').addEventListener('click', () => {
- // Remove the chat tab from state
- const editedChatTab = state.chatTabs.find(tab => tab.id === tempState.editedChatTabId);
- const editedChatTabIndex = state.chatTabs.indexOf(editedChatTab);
- state.chatTabs.splice(editedChatTabIndex, 1); // Remove the chat tab from DOM
-
- const $chatTab = document.querySelector(`[data-tab-id="${tempState.editedChatTabId}"]`);
- $chatTab.parentNode.removeChild($chatTab); // If we just removed the currently selected chat tab
-
- if (tempState.editedChatTabId === state.selectedChatTabId) {
- // Select the chat tab to the left of the removed one
- const nextChatTabIndex = editedChatTabIndex === 0 ? 0 : editedChatTabIndex - 1;
- helpers.selectChatTab(state.chatTabs[nextChatTabIndex].id);
- } // Close chat tab config
-
-
- document.querySelector('.js-chat-tab-config').style.display = 'none';
- });
- document.querySelector('.js-save-chat-tab').addEventListener('click', () => {
- // Set new chat tab name in DOM
- const $chatTab = document.querySelector(`[data-tab-id="${state.selectedChatTabId}"]`);
- const newName = document.querySelector('.js-chat-tab-name').value;
- $chatTab.textContent = newName; // Set new chat tab name in state
- // `selectedChatTab` is a reference on `state.chatTabs`, so updating it above still updates it in the state - we want to save that
-
- const selectedChatTab = state.chatTabs.find(tab => tab.id === state.selectedChatTabId);
- selectedChatTab.name = newName;
- (0, _state.saveState)(); // Close chat tab config
-
- document.querySelector('.js-chat-tab-config').style.display = 'none';
- }); // Create the initial chat tabs HTML
-
- const $chat = document.querySelector('#chat');
- const $chatTabs = (0, _misc.makeElement)({
- element: 'div',
- class: 'uimod-chat-tabs js-chat-tabs',
- content: '<div class="js-chat-tab-add">+</div>'
- }); // Add them to the DOM
-
- $chat.parentNode.insertBefore($chatTabs, $chat); // Add all our chat tabs from state
-
- state.chatTabs.forEach(chatTab => {
- const isInittingTab = true;
- helpers.addChatTab(chatTab, isInittingTab);
- }); // Wire up the add chat tab button
-
- document.querySelector('.js-chat-tab-add').addEventListener('click', clickEvent => {
- const chatTabId = helpers.addChatTab();
- const mousePos = {
- x: clickEvent.pageX,
- y: clickEvent.pageY
- };
- helpers.showChatTabConfigWindow(chatTabId, mousePos);
- }); // If initial chat tab doesn't exist, create it based off current filter settings
-
- if (!Object.keys(state.chatTabs).length) {
- const tabId = (0, _misc.uuid)();
- const chatTab = {
- name: 'Main',
- id: tabId,
- filters: helpers.getCurrentChatFilters()
- };
- state.chatTabs.push(chatTab);
- (0, _state.saveState)();
- helpers.addChatTab(chatTab);
- } // Wire up click event handlers onto the filters to update the selected chat tab's filters in state
-
-
- document.querySelector('.channelselect').addEventListener('click', clickEvent => {
- const $elementMouseIsOver = document.elementFromPoint(clickEvent.clientX, clickEvent.clientY); // We only want to change the filters if the user manually clicks the filter button
- // If they clicked a chat tab and we programatically set filters, we don't want to update
- // the current tab's filter state
-
- if (!$elementMouseIsOver.classList.contains('btn')) {
- return;
- }
-
- const selectedChatTab = state.chatTabs.find(tab => tab.id === state.selectedChatTabId);
- selectedChatTab.filters = helpers.getCurrentChatFilters();
- (0, _state.saveState)();
- }); // Select the currently selected tab in state on mod initialization
-
- if (state.selectedChatTabId) {
- helpers.selectChatTab(state.selectedChatTabId);
- }
- }
-
- var _default = {
- name: 'Chat tabs',
- description: 'Enables support for multiple chat tabs',
- run: customChatTabs
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/state":24,"./helpers":7}],9:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.dragElement = dragElement;
-
- // Credit: https://stackoverflow.com/a/14234618 (Has been slightly modified)
- // $draggedElement is the item that will be dragged.
- // $dragTrigger is the element that must be held down to drag $draggedElement
- function dragElement($draggedElement, $dragTrigger) {
- let offset = [0, 0];
- let isDown = false;
- $dragTrigger.addEventListener('mousedown', function (e) {
- isDown = true;
- offset = [$draggedElement.offsetLeft - e.clientX, $draggedElement.offsetTop - e.clientY];
- }, true);
- document.addEventListener('mouseup', function () {
- isDown = false;
- }, true);
- document.addEventListener('mousemove', function (e) {
- event.preventDefault();
-
- if (isDown) {
- $draggedElement.style.left = e.clientX + offset[0] + 'px';
- $draggedElement.style.top = e.clientY + offset[1] + 'px';
- }
- }, true);
- }
-
- },{}],10:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var _state = require("../../utils/state");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // Drag all windows by their header
- function draggableUIWindows() {
- Array.from(document.querySelectorAll('.window:not(.js-can-move)')).forEach($window => {
- $window.classList.add('js-can-move');
- helpers.dragElement($window, $window.querySelector('.titleframe'));
- });
- } // Save dragged UI windows position to state
-
-
- function saveDraggedUIWindows() {
- const state = (0, _state.getState)();
- Array.from(document.querySelectorAll('.window:not(.js-window-is-saving)')).forEach($window => {
- $window.classList.add('js-window-is-saving');
- const $draggableTarget = $window.querySelector('.titleframe');
- const windowName = $draggableTarget.querySelector('[name="title"]').textContent;
- $draggableTarget.addEventListener('mouseup', () => {
- state.windowsPos[windowName] = $window.getAttribute('style');
- (0, _state.saveState)();
- });
- });
- } // Loads draggable UI windows position from state
-
-
- function loadDraggedUIWindowsPositions() {
- const state = (0, _state.getState)();
- Array.from(document.querySelectorAll('.window:not(.js-has-loaded-pos)')).forEach($window => {
- $window.classList.add('js-has-loaded-pos');
- const windowName = $window.querySelector('[name="title"]').textContent;
- const pos = state.windowsPos[windowName];
-
- if (pos) {
- $window.setAttribute('style', pos);
- }
- });
- }
-
- var _default = {
- name: 'Draggable Windows',
- description: 'Allows you to drag windows in the UI',
- run: ({
- registerOnDomChange
- }) => {
- draggableUIWindows();
- saveDraggedUIWindows();
- loadDraggedUIWindowsPositions(); // As windows open, we want to make them draggable
-
- registerOnDomChange(saveDraggedUIWindows);
- registerOnDomChange(draggableUIWindows);
- registerOnDomChange(loadDraggedUIWindowsPositions);
- }
- };
- exports.default = _default;
-
- },{"../../utils/state":24,"./helpers":9}],11:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var player = _interopRequireWildcard(require("../../utils/player"));
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // The F icon and the UI that appears when you click it
- function customFriendsList() {
- const state = (0, _state.getState)();
- var friendsIconElement = (0, _misc.makeElement)({
- element: 'div',
- class: 'btn border black js-friends-list-icon',
- content: 'F'
- }); // Add the icon to the right of Elixir icon
-
- const $elixirIcon = document.querySelector('#sysgem');
- $elixirIcon.parentNode.insertBefore(friendsIconElement, $elixirIcon.nextSibling); // Create the friends list UI
-
- document.querySelector('.js-friends-list-icon').addEventListener('click', () => {
- if (document.querySelector('.js-friends-list')) {
- // Don't open the friends list twice.
- return;
- }
-
- let friendsListHTML = '';
- Object.keys(state.friendsList).sort().forEach(friendName => {
- friendsListHTML += `
- <div data-player-name="${friendName}">${friendName}</div>
- <div class="btn blue js-whisper-player" data-player-name="${friendName}">Whisper</div>
- <div class="btn blue js-party-player" data-player-name="${friendName}">Party invite</div>
- <div class="btn orange js-unfriend-player" data-player-name="${friendName}">X</div>
- <input type="text" class="js-friend-note" data-player-name="${friendName}" value="${state.friendNotes[friendName] || ''}"></input>
- `;
- });
- const customFriendsWindowHTML = `
- <h3 class="textprimary">Friends list</h3>
- <div class="uimod-friends">${friendsListHTML}</div>
- <p></p>
- <div class="btn purp js-close-custom-friends-list">Close</div>
- `;
- const $customFriendsList = (0, _misc.makeElement)({
- element: 'div',
- class: 'menu panel-black js-friends-list uimod-custom-window',
- content: customFriendsWindowHTML
- });
- document.body.appendChild($customFriendsList); // Wire up the buttons
-
- Array.from(document.querySelectorAll('.js-whisper-player')).forEach($button => {
- $button.addEventListener('click', clickEvent => {
- const name = clickEvent.target.getAttribute('data-player-name');
- player.whisperPlayer(name);
- });
- });
- Array.from(document.querySelectorAll('.js-party-player')).forEach($button => {
- $button.addEventListener('click', clickEvent => {
- const name = clickEvent.target.getAttribute('data-player-name');
- player.partyPlayer(name);
- });
- });
- Array.from(document.querySelectorAll('.js-unfriend-player')).forEach($button => {
- $button.addEventListener('click', clickEvent => {
- const name = clickEvent.target.getAttribute('data-player-name');
- player.unfriendPlayer(name); // Remove the blocked player from the list
-
- Array.from(document.querySelectorAll(`.js-friends-list [data-player-name="${name}"]`)).forEach($element => {
- $element.parentNode.removeChild($element);
- });
- });
- });
- Array.from(document.querySelectorAll('.js-friend-note')).forEach($element => {
- $element.addEventListener('change', clickEvent => {
- const name = clickEvent.target.getAttribute('data-player-name');
- state.friendNotes[name] = clickEvent.target.value;
- });
- }); // The close button for our custom UI
-
- document.querySelector('.js-close-custom-friends-list').addEventListener('click', () => {
- const $friendsListWindow = document.querySelector('.js-friends-list');
- $friendsListWindow.parentNode.removeChild($friendsListWindow);
- });
- });
- }
-
- var _default = {
- name: 'Friends list',
- description: 'Allows access to your friends list from the top right F icon',
- run: customFriendsList
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/player":23,"../../utils/state":24}],12:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _modStart = _interopRequireDefault(require("./_modStart"));
-
- var _blockedPlayerSettings = _interopRequireDefault(require("./blockedPlayerSettings"));
-
- var _chatContextMenu = _interopRequireDefault(require("./chatContextMenu"));
-
- var _chatFilters = _interopRequireDefault(require("./chatFilters"));
-
- var _chatTabs = _interopRequireDefault(require("./chatTabs"));
-
- var _draggableUI = _interopRequireDefault(require("./draggableUI"));
-
- var _friendsList = _interopRequireDefault(require("./friendsList"));
-
- var _mapControls = _interopRequireDefault(require("./mapControls"));
-
- var _resizableChat = _interopRequireDefault(require("./resizableChat"));
-
- var _resizableMap = _interopRequireDefault(require("./resizableMap"));
-
- var _selectedWindowIsTop = _interopRequireDefault(require("./selectedWindowIsTop"));
-
- var _xpMeter = _interopRequireDefault(require("./xpMeter"));
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- // TODO: Get /cssMods/styles.scss somehow, maybe create index.js with imported css file? Maybe separate default styles.scss outside of mods?
- // The array here dictates the order of which mods are executed, from top to bottom
- var _default = [_modStart.default, _resizableMap.default, _mapControls.default, _friendsList.default, _blockedPlayerSettings.default, _resizableChat.default, _chatFilters.default, _chatContextMenu.default, _chatTabs.default, _draggableUI.default, _selectedWindowIsTop.default, _xpMeter.default];
- exports.default = _default;
-
- },{"./_modStart":2,"./blockedPlayerSettings":3,"./chatContextMenu":5,"./chatFilters":6,"./chatTabs":8,"./draggableUI":10,"./friendsList":11,"./mapControls":14,"./resizableChat":15,"./resizableMap":17,"./selectedWindowIsTop":18,"./xpMeter":20}],13:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.updateMapOpacity = updateMapOpacity;
-
- var _state = require("../../utils/state");
-
- // On load, update map opacity to match state
- // We modify the opacity of the canvas and the background color alpha of the parent container
- // We do this to allow our opacity buttons to be visible on hover with 100% opacity
- // (A surprisingly difficult enough task to require this implementation)
- function updateMapOpacity() {
- const state = (0, _state.getState)();
- const $map = document.querySelector('.container canvas');
- const $mapContainer = document.querySelector('.js-map');
- $map.style.opacity = String(state.mapOpacity / 100);
- const mapContainerBgColor = window.getComputedStyle($mapContainer, null).getPropertyValue('background-color'); // Credit for this regexp + This opacity+rgba dual implementation: https://stackoverflow.com/questions/16065998/replacing-changing-alpha-in-rgba-javascript
-
- let opacity = state.mapOpacity / 100; // This is a slightly lazy browser workaround to fix a bug.
- // If the opacity is `1`, and it sets `rgba` to `1`, then the browser changes the
- // rgba to rgb, dropping the alpha. We could account for that and add the `alpha` back in
- // later, but setting the max opacity to very close to 1 makes sure the issue never crops up.
- // Fun fact: 0.99 retains the alpha, but setting this to 0.999 still causes the browser to drop the alpha. Rude.
-
- if (opacity === 1) {
- opacity = 0.99;
- }
-
- const newBgColor = mapContainerBgColor.replace(/[\d\.]+\)$/g, `${opacity})`);
- $mapContainer.style['background-color'] = newBgColor; // Update the button opacity
-
- const $addBtn = document.querySelector('.js-map-opacity-add');
- const $minusBtn = document.querySelector('.js-map-opacity-minus'); // Hide plus button if the opacity is max
-
- if (state.mapOpacity === 100) {
- $addBtn.style.visibility = 'hidden';
- } else {
- $addBtn.style.visibility = 'visible';
- } // Hide minus button if the opacity is lowest
-
-
- if (state.mapOpacity === 0) {
- $minusBtn.style.visibility = 'hidden';
- } else {
- $minusBtn.style.visibility = 'visible';
- }
- }
-
- },{"../../utils/state":24}],14:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- function mapControls() {
- const state = (0, _state.getState)();
- const $map = document.querySelector('.container canvas');
-
- if (!$map.parentNode.classList.contains('js-map')) {
- $map.parentNode.classList.add('js-map');
- }
-
- const $mapContainer = document.querySelector('.js-map');
- const $mapButtons = (0, _misc.makeElement)({
- element: 'div',
- class: 'js-map-btns',
- content: `
- <button class="js-map-opacity-add">+</button>
- <button class="js-map-opacity-minus">-</button>
- <button class="js-map-reset">r</button>
- `
- }); // Add it right before the map container div
-
- $map.parentNode.insertBefore($mapButtons, $map);
- helpers.updateMapOpacity();
- const $addBtn = document.querySelector('.js-map-opacity-add');
- const $minusBtn = document.querySelector('.js-map-opacity-minus');
- const $resetBtn = document.querySelector('.js-map-reset'); // Hide the buttons if map opacity is maxed/minimum
-
- if (state.mapOpacity === 100) {
- $addBtn.style.visibility = 'hidden';
- }
-
- if (state.mapOpacity === 0) {
- $minusBtn.style.visibility = 'hidden';
- } // Wire it up
-
-
- $addBtn.addEventListener('click', clickEvent => {
- // Update opacity
- state.mapOpacity += 10;
- (0, _state.saveState)();
- helpers.updateMapOpacity();
- });
- $minusBtn.addEventListener('click', clickEvent => {
- // Update opacity
- state.mapOpacity -= 10;
- (0, _state.saveState)();
- helpers.updateMapOpacity();
- });
- $resetBtn.addEventListener('click', clickEvent => {
- state.mapOpacity = 70;
- state.mapWidth = '174px';
- state.mapHeight = '174px';
- (0, _state.saveState)();
- helpers.updateMapOpacity();
- $mapContainer.style.width = state.mapWidth;
- $mapContainer.style.height = state.mapHeight;
- });
- helpers.updateMapOpacity();
- }
-
- var _default = {
- name: 'Map controls',
- description: 'Enables hovering over the minimap to show buttons that let you increase or decrease the opacity of the map, or reset the size+transparency of it',
- run: mapControls
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/state":24,"./helpers":13}],15:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- function resizableChat() {
- const state = (0, _state.getState)(); // Add the appropriate classes
-
- const $chatContainer = document.querySelector('#chat').parentNode;
- $chatContainer.classList.add('js-chat-resize'); // Load initial chat and map size
-
- if (state.chatWidth && state.chatHeight) {
- $chatContainer.style.width = state.chatWidth;
- $chatContainer.style.height = state.chatHeight;
- } // Save chat size on resize
-
-
- const resizeObserverChat = new ResizeObserver(() => {
- const chatWidthStr = window.getComputedStyle($chatContainer, null).getPropertyValue('width');
- const chatHeightStr = window.getComputedStyle($chatContainer, null).getPropertyValue('height');
- state.chatWidth = chatWidthStr;
- state.chatHeight = chatHeightStr;
- (0, _state.saveState)();
- });
- resizeObserverChat.observe($chatContainer);
- }
-
- var _default = {
- name: 'Resizable chat',
- description: 'Allows you to resize chat by clicking and dragging from the bottom right of chat',
- run: resizableChat
- };
- exports.default = _default;
-
- },{"../../utils/state":24}],16:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.onMapResize = onMapResize;
- exports.triggerMapResize = triggerMapResize;
-
- var _state = require("../../utils/state");
-
- // When the map container resizes, we want to update the canvas width/height and the state
- function onMapResize(e) {
- if (!document.querySelector('.layout')) {
- return;
- }
-
- const state = (0, _state.getState)();
- const tempState = (0, _state.getTempState)();
- const $map = document.querySelector('.container canvas').parentNode;
- const $canvas = $map.querySelector('canvas'); // Get real values of map height/width, excluding padding/margin/etc
-
- const mapWidthStr = window.getComputedStyle($map, null).getPropertyValue('width');
- const mapHeightStr = window.getComputedStyle($map, null).getPropertyValue('height');
- const mapWidth = Number(mapWidthStr.slice(0, -2));
- const mapHeight = Number(mapHeightStr.slice(0, -2)); // If height/width are 0 or unset, don't resize canvas
-
- if (!mapWidth || !mapHeight) {
- return;
- }
-
- if ($canvas.width !== mapWidth) {
- $canvas.width = mapWidth;
- }
-
- if ($canvas.height !== mapHeight) {
- $canvas.height = mapHeight;
- } // If we're clicking map, i.e. manually resizing, then save state
- // Don't save state when minimizing/maximizing map via [M]
-
-
- if (tempState.clickingMap) {
- state.mapWidth = mapWidthStr;
- state.mapHeight = mapHeightStr;
- (0, _state.saveState)();
- } else {
- const isMaximized = mapWidth > tempState.lastMapWidth && mapHeight > tempState.lastMapHeight;
-
- if (!isMaximized) {
- $map.style.width = state.mapWidth;
- $map.style.height = state.mapHeight;
- }
- } // Store last map width/height in temp state, so we know if we've minimized or maximized
-
-
- tempState.lastMapWidth = mapWidth;
- tempState.lastMapHeight = mapHeight;
- } // We need to observe canvas resizes to tell when the user presses M to open the big map
- // At that point, we resize the map to match the canvas
-
-
- function triggerMapResize() {
- if (!document.querySelector('.layout')) {
- return;
- }
-
- const $map = document.querySelector('.container canvas').parentNode;
- const $canvas = $map.querySelector('canvas'); // Get real values of map height/width, excluding padding/margin/etc
-
- const mapWidthStr = window.getComputedStyle($map, null).getPropertyValue('width');
- const mapHeightStr = window.getComputedStyle($map, null).getPropertyValue('height');
- const mapWidth = Number(mapWidthStr.slice(0, -2));
- const mapHeight = Number(mapHeightStr.slice(0, -2)); // If height/width are 0 or unset, we don't care about resizing yet
-
- if (!mapWidth || !mapHeight) {
- return;
- }
-
- if ($canvas.width !== mapWidth) {
- $map.style.width = `${$canvas.width}px`;
- }
-
- if ($canvas.height !== mapHeight) {
- $map.style.height = `${$canvas.height}px`;
- }
- }
-
- },{"../../utils/state":24}],17:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- function resizableMap() {
- const state = (0, _state.getState)();
- const tempState = (0, _state.getTempState)();
- const $map = document.querySelector('.container canvas').parentNode;
- const $canvas = $map.querySelector('canvas');
- $map.classList.add('js-map-resize'); // Track whether we're clicking (resizing) map or not
- // Used to detect if resize changes are manually done, or from minimizing/maximizing map (with [M])
-
- $map.addEventListener('mousedown', () => {
- tempState.clickingMap = true;
- }); // Sometimes the mouseup event may be registered outside of the map - we account for this
-
- document.body.addEventListener('mouseup', () => {
- tempState.clickingMap = false;
- });
-
- if (state.mapWidth && state.mapHeight) {
- $map.style.width = state.mapWidth;
- $map.style.height = state.mapHeight;
- helpers.onMapResize(); // Update canvas size on initial load of saved map size
- } // On resize of map, resize canvas to match
- // Debouncing allows map to be visible while resizing
-
-
- const debouncedMapResize = (0, _misc.debounce)(helpers.onMapResize, 1);
- const resizeObserverMap = new ResizeObserver(debouncedMapResize);
- helpers.onMapResize();
- resizeObserverMap.observe($map); // We debounce the canvas resize, so it doesn't resize every single
- // pixel you move when resizing the DOM. If this were to happen,
- // resizing would constantly be interrupted. You'd have to resize a tiny bit,
- // lift left click, left click again to resize a tiny bit more, etc.
- // Resizing is smooth when we debounce this canvas.
-
- const debouncedTriggerResize = (0, _misc.debounce)(helpers.triggerMapResize, 50);
- const resizeObserverCanvas = new ResizeObserver(debouncedTriggerResize);
- resizeObserverCanvas.observe($canvas);
- }
-
- var _default = {
- name: 'Resizable map',
- description: 'Allows you to resize the map by clicking and dragging from the bottom left',
- run: resizableMap
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/state":24,"./helpers":16}],18:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- // The last clicked UI window displays above all other UI windows
- // This is useful when, for example, your inventory is near the market window,
- // and you want the window and the tooltips to display above the market window.
- function selectedWindowIsTop() {
- Array.from(document.querySelectorAll('.window:not(.js-is-top-initd)')).forEach($window => {
- $window.classList.add('js-is-top-initd');
- $window.addEventListener('mousedown', () => {
- // First, make the other is-top window not is-top
- const $otherWindowContainer = document.querySelector('.js-is-top');
-
- if ($otherWindowContainer) {
- $otherWindowContainer.classList.remove('js-is-top');
- } // Then, make our window's container (the z-index container) is-top
-
-
- $window.parentNode.classList.add('js-is-top');
- });
- });
- }
-
- var _default = {
- name: 'Make Selected Window Top',
- description: 'The UI window you click will always be displayed over other UI windows',
- run: ({
- registerOnDomChange
- }) => {
- selectedWindowIsTop(); // As windows are opened, we want to enable them to become the top window when they're clicked
-
- registerOnDomChange(selectedWindowIsTop);
- }
- };
- exports.default = _default;
-
- },{}],19:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.getCurrentCharacterLvl = getCurrentCharacterLvl;
- exports.getCurrentXp = getCurrentXp;
- exports.getNextLevelXp = getNextLevelXp;
- exports.resetXpMeterState = resetXpMeterState;
- exports.toggleXpMeterVisibility = toggleXpMeterVisibility;
- exports.msToString = msToString;
-
- var _state = require("../../utils/state");
-
- function getCurrentCharacterLvl() {
- return Number(document.querySelector('#ufplayer .bgmana > .left').textContent.split('Lv. ')[1]);
- }
-
- function getCurrentXp() {
- return Number(document.querySelector('#expbar .progressBar > .left').textContent.split('/')[0].trim());
- }
-
- function getNextLevelXp() {
- return Number(document.querySelector('#expbar .progressBar > .left').textContent.split('/')[1].trim());
- } // user invoked reset of xp meter stats
-
-
- function resetXpMeterState() {
- const state = (0, _state.getState)();
- state.xpMeterState.xpGains = []; // array of xp deltas every second
-
- state.xpMeterState.averageXp = 0;
- state.xpMeterState.gainedXp = 0;
- (0, _state.saveState)();
- document.querySelector('.js-xp-time').textContent = '-:-:-';
- } // toggle the xp meter
-
-
- function toggleXpMeterVisibility() {
- const xpMeterContainer = document.querySelector('.js-xpmeter');
- xpMeterContainer.style.display = xpMeterContainer.style.display === 'none' ? 'block' : 'none';
- }
-
- function msToString(ms) {
- const pad = value => value < 10 ? `0${value}` : value;
-
- const hours = pad(Math.floor(ms / (1000 * 60 * 60) % 60));
- const minutes = pad(Math.floor(ms / (1000 * 60) % 60));
- const seconds = pad(Math.floor(ms / 1000 % 60));
- return `${hours}:${minutes}:${seconds}`;
- }
-
- },{"../../utils/state":24}],20:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
-
- var _state = require("../../utils/state");
-
- var helpers = _interopRequireWildcard(require("./helpers"));
-
- var _misc = require("../../utils/misc");
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- // Adds XP Meter DOM icon and window, starts continuous interval to get current xp over time
- function xpMeter() {
- const state = (0, _state.getState)();
- const tempState = (0, _state.getTempState)();
- const $layoutContainer = document.querySelector('body > div.layout > div.container:nth-child(1)');
- const $dpsMeterToggleElement = document.querySelector('#systrophy');
- const $xpMeterToggleElement = (0, _misc.makeElement)({
- element: 'div',
- class: 'js-sysxp js-xpmeter-icon btn border black',
- content: 'XP'
- });
- const xpMeterHTMLString = `
- <div class="l-corner-lr container uimod-xpmeter-1 js-xpmeter" style="display: none">
- <div class="window panel-black uimod-xpmeter-2">
- <div class="titleframe uimod-xpmeter-2">
- <img src="/assets/ui/icons/trophy.svg?v=3282286" class="titleicon svgicon uimod-xpmeter-2">
- <div class="textprimary title uimod-xpmeter-2">
- <div name="title">Experience / XP</div>
- </div>
- <img src="/assets/ui/icons/cross.svg?v=3282286" class="js-xpmeter-close-icon btn black svgicon">
- </div>
- <div class="slot uimod-xpmeter-2" style="">
- <div class="wrapper uimod-xpmeter-1">
- <div class="bar uimod-xpmeter-3" style="z-index: 0;">
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">XP per minute:</span>
- <span class="right uimod-xpmeter-3 js-xpm">-</span>
- </div>
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">XP per hour:</span>
- <span class="right uimod-xpmeter-3 js-xph">-</span>
- </div>
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">XP Gained:</span>
- <span class="right uimod-xpmeter-3 js-xpg">-</span>
- </div>
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">XP Left:</span>
- <span class="right uimod-xpmeter-3 js-xpl">-</span>
- </div>
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">Session Time: </span>
- <span class="right uimod-xpmeter-3 js-xp-s-time">-</span>
- </div>
- <div class="progressBar bgc1 uimod-xpmeter-3" style="width: 100%; font-size: 1em;">
- <span class="left uimod-xpmeter-3">Time to lvl: </span>
- <span class="right uimod-xpmeter-3 js-xp-time">-</span>
- </div>
- </div>
- </div>
- <div class="grid buttons marg-top uimod-xpmeter-1 js-xpmeter-reset-button">
- <div class="btn grey">Reset</div>
- </div>
- </div>
- </div>
- </div>
- `;
- $dpsMeterToggleElement.parentNode.insertBefore($xpMeterToggleElement, $dpsMeterToggleElement.nextSibling);
- const $xpMeterElement = (0, _misc.makeElement)({
- element: 'div',
- content: xpMeterHTMLString.trim()
- });
- $layoutContainer.appendChild($xpMeterElement.firstChild); // Wire up icon and xpmeter window
-
- document.querySelector('.js-sysxp').addEventListener('click', helpers.toggleXpMeterVisibility);
- document.querySelector('.js-xpmeter-close-icon').addEventListener('click', helpers.toggleXpMeterVisibility);
- document.querySelector('.js-xpmeter-reset-button').addEventListener('click', helpers.resetXpMeterState);
- state.xpMeterState.currentXp = helpers.getCurrentXp();
- state.xpMeterState.currentLvl = helpers.getCurrentCharacterLvl();
- (0, _state.saveState)();
- if (tempState.xpMeterInterval) clearInterval(tempState.xpMeterInterval); // every second we run the operations for xp meter, update xps, calc delta, etc
- // TODO Cleanup: This interval may not be cleaned up if the UI mod reinitializes,
- // e.g. user is away from tab for a while then comes back
- // Should confirm if this is an issue, and try to fix it if possible.
-
- tempState.xpMeterInterval = setInterval(() => {
- if (!document.querySelector('#expbar')) {
- return;
- }
-
- const currentXp = helpers.getCurrentXp();
- const nextLvlXp = helpers.getNextLevelXp();
- const currentLvl = helpers.getCurrentCharacterLvl();
- state.xpMeterState.gainedXp += currentXp - state.xpMeterState.currentXp;
- state.xpMeterState.xpGains.push(currentXp - state.xpMeterState.currentXp); // array of xp deltas every second
-
- state.xpMeterState.currentXp = currentXp;
- state.xpMeterState.averageXp = state.xpMeterState.xpGains.reduce((a, b) => a + b) / state.xpMeterState.xpGains.length;
- (0, _state.saveState)();
-
- if (document.querySelector('.js-xpmeter')) {
- document.querySelector('.js-xpm').textContent = parseInt((state.xpMeterState.averageXp * 60).toFixed(0)).toLocaleString();
- document.querySelector('.js-xph').textContent = parseInt((state.xpMeterState.averageXp * 60 * 60).toFixed(0)).toLocaleString();
- document.querySelector('.js-xpg').textContent = state.xpMeterState.gainedXp.toLocaleString();
- document.querySelector('.js-xpl').textContent = (nextLvlXp - currentXp).toLocaleString();
- document.querySelector('.js-xp-s-time').textContent = helpers.msToString(state.xpMeterState.xpGains.length * 1000); // need a positive integer for averageXp to calc time left
-
- if (state.xpMeterState.averageXp > 0) document.querySelector('.js-xp-time').textContent = helpers.msToString((nextLvlXp - currentXp) / state.xpMeterState.averageXp * 1000);
- }
-
- if (state.xpMeterState.currentLvl < currentLvl) {
- helpers.resetXpMeterState();
- state.xpMeterState.currentLvl = currentLvl;
- (0, _state.saveState)();
- }
- }, 1000);
- }
-
- var _default = {
- name: 'XP Meter',
- description: "Tracks your XP/minute and displays how much XP you're getting and lets you know how long until you level up",
- run: xpMeter
- };
- exports.default = _default;
-
- },{"../../utils/misc":22,"../../utils/state":24,"./helpers":19}],21:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.setGMChatVisibility = setGMChatVisibility;
- exports.filterAllChat = filterAllChat;
- exports.whisperPlayer = whisperPlayer;
- exports.partyPlayer = partyPlayer;
- exports.addChatMessage = addChatMessage;
-
- var _state = require("./state");
-
- var _misc = require("./misc");
-
- // Updates state.chat.GM and the DOM to make text white/grey depending on if gm chat is visible/filtered
- // Then filters chat and saves updated chat state
- function setGMChatVisibility(isGMChatVisible) {
- const state = (0, _state.getState)();
- const $chatGM = document.querySelector(`.js-chat-gm`);
- state.chat.GM = isGMChatVisible;
- $chatGM.classList.toggle('textgrey', !state.chat.GM);
- filterAllChat();
- (0, _state.saveState)();
- } // Filters all chat based on custom filters
-
-
- function filterAllChat() {
- const state = (0, _state.getState)(); // Blocked user filter
-
- Object.keys(state.blockList).forEach(blockedName => {
- // Get the `.name` elements from the blocked user, if we haven't already hidden their messages
- const $blockedChatNames = Array.from(document.querySelectorAll(`[data-chat-name="${blockedName}"]:not(.js-line-blocked)`)); // Hide each of their messages
-
- $blockedChatNames.forEach($name => {
- // Add the class name to $name so we can track whether it's been hidden in our CSS selector $blockedChatNames
- $name.classList.add('js-line-blocked');
- const $line = $name.parentNode.parentNode.parentNode; // Add the class name to $line so we can visibly hide the entire chat line
-
- $line.classList.add('js-line-blocked');
- });
- }); // Custom channel filter
-
- Object.keys(state.chat).forEach(channel => {
- Array.from(document.querySelectorAll(`.text${channel}.content`)).forEach($textItem => {
- const $line = $textItem.parentNode.parentNode;
- $line.classList.toggle('js-line-hidden', !state.chat[channel]);
- });
- });
- }
-
- function enterTextIntoChat(text) {
- // Open chat input
- const enterEvent = new KeyboardEvent('keydown', {
- bubbles: true,
- cancelable: true,
- keyCode: 13
- });
- document.body.dispatchEvent(enterEvent); // Place text into chat
-
- const $input = document.querySelector('#chatinput input');
- $input.value = text; // Get chat input to recognize slash commands and change the channel
- // by triggering the `input` event.
- // (Did some debugging to figure out the channel only changes when the
- // svelte `input` event listener exists.)
-
- const inputEvent = new KeyboardEvent('input', {
- bubbles: true,
- cancelable: true
- });
- $input.dispatchEvent(inputEvent);
- }
-
- function submitChat() {
- const $input = document.querySelector('#chatinput input');
- const kbEvent = new KeyboardEvent('keydown', {
- bubbles: true,
- cancelable: true,
- keyCode: 13
- });
- $input.dispatchEvent(kbEvent);
- } // Automated chat command helpers
- // (We've been OK'd to do these by the dev - all automation like this should receive approval from the dev)
-
-
- function whisperPlayer(playerName) {
- enterTextIntoChat(`/${playerName} `);
- }
-
- function partyPlayer(playerName) {
- enterTextIntoChat(`/partyinvite ${playerName}`);
- submitChat();
- } // Pushes message to chat
- // TODO: The margins for the message are off slightly compared to other messages - why?
-
-
- function addChatMessage(text) {
- const newMessageHTML = `
- <div class="linewrap svelte-1vrlsr3">
- <span class="time svelte-1vrlsr3">00.00</span>
- <span class="textuimod content svelte-1vrlsr3">
- <span class="capitalize channel svelte-1vrlsr3">UIMod</span>
- </span>
- <span class="svelte-1vrlsr3">${text}</span>
- </div>
- `;
- const element = (0, _misc.makeElement)({
- element: 'article',
- class: 'line svelte-1vrlsr3',
- content: newMessageHTML
- });
- document.querySelector('#chat').appendChild(element);
- }
-
- },{"./misc":22,"./state":24}],22:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.makeElement = makeElement;
- exports.debounce = debounce;
- exports.uuid = uuid;
-
- // Nicer impl to create elements in one method call
- function makeElement(args) {
- const $node = document.createElement(args.element);
-
- if (args.class) {
- $node.className = args.class;
- }
-
- if (args.content) {
- $node.innerHTML = args.content;
- }
-
- if (args.src) {
- $node.src = args.src;
- }
-
- return $node;
- } // Credit: David Walsh
-
-
- function debounce(func, wait, immediate) {
- var timeout;
- return function () {
- var context = this,
- args = arguments;
-
- var later = function () {
- timeout = null;
- if (!immediate) func.apply(context, args);
- };
-
- var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) func.apply(context, args);
- };
- } // Credit: https://gist.github.com/jcxplorer/823878
- // Generate random UUID string
-
-
- function uuid() {
- var uuid = '',
- i,
- random;
-
- for (i = 0; i < 32; i++) {
- random = Math.random() * 16 | 0;
-
- if (i == 8 || i == 12 || i == 16 || i == 20) {
- uuid += '-';
- }
-
- uuid += (i == 12 ? 4 : i == 16 ? random & 3 | 8 : random).toString(16);
- }
-
- return uuid;
- }
-
- },{}],23:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.friendPlayer = friendPlayer;
- exports.unfriendPlayer = unfriendPlayer;
- exports.blockPlayer = blockPlayer;
- exports.unblockPlayer = unblockPlayer;
-
- var _state = require("./state");
-
- var chat = _interopRequireWildcard(require("./chat"));
-
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
- function friendPlayer(playerName) {
- const state = (0, _state.getState)();
-
- if (state.friendsList[playerName]) {
- return;
- }
-
- state.friendsList[playerName] = true;
- chat.addChatMessage(`${playerName} has been added to your friends list.`);
- (0, _state.saveState)();
- }
-
- function unfriendPlayer(playerName) {
- const state = (0, _state.getState)();
-
- if (!state.friendsList[playerName]) {
- return;
- }
-
- delete state.friendsList[playerName];
- delete state.friendNotes[playerName];
- chat.addChatMessage(`${playerName} is no longer on your friends list.`);
- (0, _state.saveState)();
- } // Adds player to block list, to be filtered out of chat
-
-
- function blockPlayer(playerName) {
- const state = (0, _state.getState)();
-
- if (state.blockList[playerName]) {
- return;
- }
-
- state.blockList[playerName] = true;
- chat.filterAllChat();
- chat.addChatMessage(`${playerName} has been blocked.`);
- (0, _state.saveState)();
- } // Removes player from block list and makes their messages visible again
-
-
- function unblockPlayer(playerName) {
- const state = (0, _state.getState)();
- delete state.blockList[playerName];
- chat.addChatMessage(`${playerName} has been unblocked.`);
- (0, _state.saveState)(); // Make messages visible again
-
- const $chatNames = Array.from(document.querySelectorAll(`.js-line-blocked[data-chat-name="${playerName}"]`));
- $chatNames.forEach($name => {
- $name.classList.remove('js-line-blocked');
- const $line = $name.parentNode.parentNode.parentNode;
- $line.classList.remove('js-line-blocked');
- });
- }
-
- },{"./chat":21,"./state":24}],24:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.getState = getState;
- exports.getTempState = getTempState;
- exports.saveState = saveState;
- exports.loadState = loadState;
-
- var _version = require("./version");
-
- const STORAGE_STATE_KEY = 'hordesio-uimodsakaiyo-state'; // Manually saved in local state
-
- const state = {
- breakingVersion: _version.BREAKING_VERSION,
- chat: {
- GM: true
- },
- windowsPos: {},
- blockList: {},
- friendsList: {},
- mapOpacity: 70,
- // e.g. 70 = opacity: 0.7
- friendNotes: {},
- chatTabs: [],
- xpMeterState: {
- currentXp: 0,
- xpGains: [],
- // array of xp deltas every second
- averageXp: 0,
- gainedXp: 0,
- currentLvl: 0
- }
- }; // tempState is saved only between page refreshes.
-
- const tempState = {
- // The last name clicked in chat
- chatName: null,
- lastMapWidth: 0,
- lastMapHeight: 0,
- xpMeterInterval: null // tracks the interval for fetching xp data
-
- };
-
- function getState() {
- return state;
- }
-
- function getTempState() {
- return tempState;
- }
-
- function saveState() {
- localStorage.setItem(STORAGE_STATE_KEY, JSON.stringify(state));
- }
-
- function loadState() {
- const storedStateJson = localStorage.getItem(STORAGE_STATE_KEY);
-
- if (storedStateJson) {
- const storedState = JSON.parse(storedStateJson);
-
- if (storedState.breakingVersion !== _version.BREAKING_VERSION) {
- localStorage.setItem(STORAGE_STATE_KEY, JSON.stringify(state));
- return;
- }
-
- for (let [key, value] of Object.entries(storedState)) {
- state[key] = value;
- }
- }
- }
-
- },{"./version":25}],25:[function(require,module,exports){
- "use strict";
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.VERSION = exports.BREAKING_VERSION = void 0;
- // If this version is different from the user's stored state,
- // e.g. they have upgraded the version of this script and there are breaking changes,
- // then their stored state will be deleted.
- const BREAKING_VERSION = 1; // Used for initialization message in chat, and userscript version
-
- exports.BREAKING_VERSION = BREAKING_VERSION;
- const VERSION = '1.0.2';
- exports.VERSION = VERSION;
-
- },{}]},{},[1]);