MediaWiki:Gadget-idle-util.js: Difference between revisions

From Idle Clans wiki
No edit summary
No edit summary
 
Line 94: Line 94:
* @param  {number} number
* @param  {number} number
*          The number to format.
*          The number to format.
* @param  {number} decimals
* @param  {number} [decimals]
*          The number of decimals to display.
*          The number of decimals to display.
*  
*  

Latest revision as of 07:23, 11 June 2024

// REQUIRES oojs-ui-widgets
;(function($, mw, idleClans) {
	idleClans.util = {

		/**
		 * If we should print debug information to the console.
		 */
		DEBUG: false,

		/**
		 * Send a debug message to the console.
		 *
		 * @param   {...*} arguments
		 *          The arguments to log.
		 */
		debug: function() {
			if (!this.DEBUG) return;
			var args = Array.prototype.slice.call(arguments);
			console.log.apply(console, ["DEBUG:"].concat(args));
		},

		/**
		 * The gemstone prefixes for each tier.
		 */
		GEMSTONE_PREFIXES: [ "Normal", "Refined", "Great", "Elite", "Superior", "Outstanding", "Godlike" ],

		/**
		 * Get the refined name for the given name and tier.
		 *
		 * If the tier is out of bounds, an error is logged and the name is
		 * returned with an error prefix.
		 *
		 * @param   {string} name
		 *          The name to prepend the prefix to.
		 * @param   {number} tier
		 *          The tier of the gemstone.
		 *
		 * @returns {string}
		 *          The refined name.
		 */
		getRefinedName: function(name, tier) {
			if (tier < 0 || tier >= this.GEMSTONE_PREFIXES.length) {
				mw.error("getRefinedName: Tier out of bounds (" + tier + ", " + this.GEMSTONE_PREFIXES.length + ")");
				return "Err " + name;
			}
			return this.GEMSTONE_PREFIXES[tier] + " " + name;
		},

		// utils.tierify(["House", "Mansion", "Castle"]);
		// utils.tierify([function(i) { return NAMES[i]; }, 10]);

		/**
		 * Tierify the given supplier, adding "T1", "T2", etc. to the names.
		 *
		 * @param   {[function(number): string, number]|string[]} supplier
		 *          Either a tuple containing a function and a number, or an array
		 *          of names to tierify. If a tuple is provided, the function will
		 *          be used to supply the names based on the index, with the number
		 *          specifying how many tiers to create.
		 * @param   {string[]|string} [prepend]
		 *          Optionally, an array of names to prepend to the tier array.
		 * @param   {string[]|string} [append]
		 *          Optionally, an array of names to append to the tier array.
		 */
		tierify: function(supplier, prepend, append) {
			prepend = prepend || [];
			append = append || [];
			if (!Array.isArray(prepend)) prepend = [prepend];
			if (!Array.isArray(append)) append = [append];

			// Get the names from the supplier.
			var names = supplier;
			if (typeof supplier[0] === 'function') {
				names = [];
				var nameSupplier = supplier[0];
				var tierCount = supplier[1];

				for (var i = 0; i < tierCount; i++)
					names.push(nameSupplier(i));
			}

			// Tierify the names.
			var tiered = names.map(function(name, index) {
				return "(T" + (index + 1) + ") " + name;
			});

			// Add the prepended and appended names.
			return prepend.concat(tiered, append);
		},

		/**
		 * Format the given number with commas.
		 *
		 * @param   {number} number
		 *          The number to format.
		 * @param   {number} [decimals]
		 *          The number of decimals to display.
		 * 
		 * @returns {string}
		 *          The formatted number.
		 */
		formatNumber: function(number, decimals) {
			decimals = decimals || 2;
			return new Intl.NumberFormat('en-US', { maximumFractionDigits: decimals }).format(number);
		},

		number: {
			/**
			 * Round the given value to the specified number of decimals using
			 * bankers rounding.
			 *
			 * This is mainly used by calculators to ensure the values are the
			 * same as the game (C# uses bankers rounding by default).
			 *
			 * @param   {number} value
			 *          The value to round.
			 * @param   {number} decimals
			 *          The maximum number of decimals to display.
			 *
			 * @returns {number}
			 *          The rounded value.
			 */
			bankersRound: function(value, decimals) {
				value = parseFloat(value.toFixed(6)); // Try to fix floating point errors.
				decimals = decimals || 2; // Default to 2 decimal places.

				var x = value * Math.pow(10, decimals);
				var r = Math.round(x);
				var br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r-1) : r;
				return br / Math.pow(10, decimals);
			},

			/**
			 * Round the given value to the specified number of decimals, removing
			 * any trailing zeros if necessary.
			 *
			 * @param   {number} value
			 *          The value to round.
			 * @param   {number} decimals
			 *          The maximum number of decimals to display.
			 *
			 * @returns {number}
			 *          The rounded value.
			 */
			toFixedSmall: function(value, decimals) {
				return parseFloat(value.toFixed(decimals));
			}
		},

		ui: {

			/**
			 * Create a dropdown widget with the given items and optionally the
			 * selected item.
			 *
			 * @param   {(string|{label:string,header:boolean=,disabled:boolean=,hidden:boolean=})[]} items
			 *          The items to display in the dropdown widget.
			 * @param   {number} [selected]
			 *          Optionally, the index of the selected item.
			 * @param   {string} [label]
			 *          Optionally, the label for the dropdown widget.
			 *
			 * @returns {OO.ui.DropdownWidget}
			 *          The dropdown widget.
			 */
			dropdown: function(items, selected, label) {
				var currentIndex = 0;
				var dropdown = new OO.ui.DropdownWidget({
					label: label,
					menu: {
						items: items.map(function (item, index) {
							if (typeof item === 'string')
								return new OO.ui.MenuOptionWidget({ data: currentIndex++, label: item });

							var label = item.label || "Unknown";
							var header = item.header || false;
							var disabled = item.disabled || false;
							var hidden = item.hidden || false;

							if (header) {
								label = $("<div style='text-align:center'>" + label + "</div>");
								return new OO.ui.MenuSectionOptionWidget( { label: label } );
							}

							if (!hidden)
								return new OO.ui.MenuOptionWidget({ data: currentIndex++, label: label,
									disabled: disabled });

							return new OO.ui.MenuOptionWidget({ data: currentIndex++, label: label, disabled: disabled,
								invisibleLabel: hidden, $element: $("<div style='display:none'></div>") });
						})
					}
				});

				// We need to override the "below" key to have value "below".
				// If we don't then it might go above the dropdown and hide
				// items behind the navbar.
				OO.ui.MenuSelectWidget.static.flippedPositions = {
					below: 'below',
					above: 'below',
					top: 'bottom',
					bottom: 'top'
				};

				if (selected !== undefined && typeof selected === 'number') {
					if (selected < 0 || selected >= items.length)
						mw.error("UI.dropdown: Selected index out of bounds (" + selected + ", " + items.length + ")");
					else dropdown.getMenu().selectItemByData(selected);
				}

				return dropdown;
			},

			/**
			 * Create a button widget with the given label and flags.
			 *
			 * @param   {string} [label]
			 *          Optionally, the label for the button.
			 * @param   {string[]} [flags]
			 *          Optionally, the flags for the button.
			 *
			 * @returns {OO.ui.ButtonWidget}
			 *          The button widget.
			 */
			button: function(label, flags) {
				label = label || "Button";
				flags = flags || [];
				return new OO.ui.ButtonWidget({ label: label, flags: flags });
			},

			/**
			 * Create a button input widget with the given label and flags.
			 *
			 * @param   {string} [label]
			 *          Optionally, the label for the button.
			 * @param   {string[]} [flags]
			 *          Optionally, the flags for the button.
			 *
			 * @returns {OO.ui.ButtonInputWidget}
			 *          The button input widget.
			 */
			buttonInput: function(label, flags) {
				label = label || "Button";
				flags = flags || [];
				return new OO.ui.ButtonInputWidget({ label: label, flags: flags });
			},

			/**
			 * Create a checkbox widget with an optional label and selected
			 * state.
			 *
			 * @param   {boolean} [selected]
             *          Optionally, whether the checkbox is selected.
			 * @param   {string} [label]
			 *          Optionally, the label for the checkbox.
			 *
			 * @returns {OO.ui.CheckboxInputWidget|OO.ui.FieldLayout}
			 *          The checkbox widget, or a field layout with the checkbox
			 *          and the label.
			 */
			checkbox: function(selected, label) {
				var checkbox = new OO.ui.CheckboxInputWidget({ selected: selected });

				if (label !== undefined && typeof label === 'string') {
					return new OO.ui.FieldLayout(checkbox, { label: label, align: 'inline' });
				}

				return checkbox;
			},

			/**
			 * Create a toggle switch widget with an optional initial state.
			 *
			 * @param   {boolean} [switched]
			 *          Optionally, whether the switch is on.
			 *
			 * @returns {OO.ui.ToggleSwitchWidget}
			 *          The toggle switch widget.
			 */
			switch: function(switched) {
				switched = switched || false;
				return new OO.ui.ToggleSwitchWidget({ value: switched });
			}
		}
	}
})(window.jQuery, window.mw, window.idleClans = window.idleClans || {});