Raw Source
rsenderak / AtmoBurn Services - labels

// ==UserScript==
// @name        AtmoBurn Services - labels
// @namespace   sk.seko
// @license     MIT
// @description	Rename fleet or colony; visible only localy (in your browser) - it's a client side "rename"
// @updateURL   https://openuserjs.org/meta/rsenderak/abs-labels.meta.js
// @downloadURL https://openuserjs.org/install/rsenderak/abs-labels.user.js
// @match       https://*.atmoburn.com/*
// @exclude    	https://*.atmoburn.com/extras/view_universe.php*
// @version	    2.2
// @grant       none
// ==/UserScript==

// v1.0 - script published at openuserjs.org
// v1.1 - all fleet and colony names are replaced (by labels, if defined) on any page
// v1.2 - fixed bug where original name was not displayed as tooltip, sometimes
// v1.2.1 - esversion set to 11
// v2.0 - new storage format (migrated automatically); small fixes
// v2.1 - excluded universe map (at least for now)
// v2.1.1 - small fix for modal windows
// v2.2 - migrated data (from 1.x) are fixed when detail screen is opened for the first time

/* jshint esversion: 11 */
/* jshint node: true */

"use strict";

const WF_BASE_URL=`https://${window.location.host}`;

// local DB (browser database) keys
const KEY_FLEET_LABELS = "abs.fleetLabels";
const KEY_COLONY_LABELS = "abs.colonyLabels";

// global variables (fleets)
var fleetId = parseFleetIDFromURL(); // fleet ID from URL; or null if not on the right page
var fleetHeadline = fleetId ? byId("pageHeadLine") : null; // fleet name element from fleet detail page; or null

// global variables (colonies)
var colonyId = parseColonyIDFromURL(); // colony ID from URL; or null if not on the right page
var colonyHeadline = colonyId ? byId("midcolumn").querySelector(".pagetitle") : null; // colony name element from colony detail page; or null


// Get element by ID.
function byId(ele) {
  return document.getElementById(ele);
}

function getFleetLabels() {
	const v = localStorage.getItem(KEY_FLEET_LABELS);
	return v ? JSON.parse(v) : {};
}

function getColonyLabels() {
	const v = localStorage.getItem(KEY_COLONY_LABELS);
	return v ? JSON.parse(v) : {};
}

// set new "label" for record ID "rid", with original name "current"; remove label if label=null
function storeLabel(key, labelMap, rid, label, current) {
	if (label) { // set label
		const rec = labelMap[rid];
		if (rec) { // label existed, just replace it
			rec.l = label;
		} else { // no label, store label and original name as well
			labelMap[rid] = {"l": label, "n": current};
		}
	} else { // remove label
		delete labelMap[rid];
	}
	localStorage.setItem(key, JSON.stringify(labelMap));
	return labelMap[rid];
}

function parseFleetIDFromURL() {
	let m = document.URL.match(/(?:[\?\&]fleet=|\/fleet\/)(\d+)/);
	if (m && m[1]) {
		return parseInt(m[1]);
	}
	return null;
}

function parseColonyIDFromURL() {
	let m = document.URL.match(/[\?\&]colony=(\d+)/);
	if (m && m[1]) {
		return parseInt(m[1]);
	}
	return null;
}

// set or reset label; original "name" is stored in (or restored from) "title" attribute
function displayLabel(node, label) {
	if (label) { // set new label
		node.innerHTML = label;
	}
}

// TEMPORARY: check/fix original name if migrated
function checkMigration(labelMap, key, node, record) {
	if (record && record.l == record.n) {
		try {
			if (node.innerHTML && node.innerHTML != record.n) {
				console.log(`ABS-label: Fixing migrated from "${record.n}" to "${node.innerHTML}"`);
				record.n = node.innerHTML;
				localStorage.setItem(key, JSON.stringify(labelMap));
			}
		} catch (error) {
			console.error(error);
		}
	}
}

function displayFleetLabel(fid, label, oldLabel) {
	if (label) {
		document.querySelectorAll(`a[href*="fleet=${fid}"]`).forEach((node) => {
			try {
				const m = node.href.match(/\/fleet\.php.*\Wfleet=(\d+)/);
				// replace only if URL really matches
				if (m && fid == parseInt(m[1])) {
					// and if content matches oldLabel (FIXME: for migrated values, there is a hack: label == oldLabel
					if (!oldLabel || label == oldLabel || node.textContent == oldLabel) {
						displayLabel(node, label);
					}
				}
			} catch (error) {
				console.error(error);
			}
		});
	}
}

function displayColonyLabel(cid, label, oldLabel) {
	if (label) {
		document.querySelectorAll(`a[href*="colony=${cid}"]`).forEach((node) => {
			try {
				const m = node.href.match(/\/view_colony\.php.*\Wcolony=(\d+)/);
				// replace only if URL really matches
				if (m && cid == parseInt(m[1])) {
					// and if content matches oldLabel (FIXME: for migrated values, there is a hack: label == oldLabel
					if (!oldLabel || label == oldLabel || node.textContent == oldLabel) {
						displayLabel(node, label);
					}
				}
			} catch (error) {
				console.error(error);
			}
		});
	}
}

function displayFleetLabels() {
	const labelMap = getFleetLabels();
	Object.entries(labelMap).forEach(([rid, record]) => {
		displayFleetLabel(rid, record.l, record.n);
	});
	if (fleetId && fleetHeadline) {
		checkMigration(labelMap, KEY_FLEET_LABELS, fleetHeadline, labelMap[fleetId]);
		displayLabel(fleetHeadline, labelMap[fleetId]?.l);
	}
}

function displayColonyLabels() {
	const labelMap = getColonyLabels();
	Object.entries(labelMap).forEach(([rid, record]) => {
		displayColonyLabel(rid, record.l, record.n);
	});
	if (colonyId && colonyHeadline) {
		checkMigration(labelMap, KEY_COLONY_LABELS, colonyHeadline, labelMap[colonyId]);
		displayLabel(colonyHeadline, labelMap[colonyId]?.l);
	}
}

function editFleetLabel() {
	const headlineText = fleetHeadline.textContent?.trim();
	let val = prompt("New name, or empty string for original name", headlineText);
	if (val === null) {
		return; // dialog cancelled; quitting
	}
	const labelMap = getFleetLabels();
	let record = labelMap[fleetId];
	// reset to original name
	if (record) {
		displayFleetLabel(fleetId, record.n, record.l);
		displayLabel(fleetHeadline, record.n);
	}
	// store new label
	record = storeLabel(KEY_FLEET_LABELS, labelMap, fleetId, val, headlineText);
	// display new label
	if (record) {
		displayFleetLabel(fleetId, record.l, record.n);
		displayLabel(fleetHeadline, record.l);
	}
}

function editColonyLabel() {
	const headlineText = colonyHeadline.textContent?.trim();
	let val = prompt("New name, or empty string for original name", headlineText);
	if (val === null) {
		return; // dialog cancelled; quitting
	}
	const labelMap = getColonyLabels();
	let record = labelMap[colonyId];
	// reset to original name
	if (record) {
		displayColonyLabel(colonyId, record.n, record.l);
		displayLabel(colonyHeadline, record.n);
	}
	// store new label
	record = storeLabel(KEY_COLONY_LABELS, labelMap, colonyId, val, headlineText);
	// display new label
	if (record) {
		displayColonyLabel(colonyId, record.l, record.n);
		displayLabel(colonyHeadline, record.l);
	}
}

function addLabelEditIcon(headline, callback) {
	const tooltip = "Change the name; enter empty string to reset it back to original";
	const editIcon = document.createElement('span');
	editIcon.innerHTML = `&nbsp;<span id="labelEdit" style="font-size: 50%" class="fa-light fa-pen" title="${tooltip}"></span>`;
	headline.after(editIcon);
	byId("labelEdit").addEventListener('click', callback);
}

function addFleetLabelEditIcon() {
	addLabelEditIcon(fleetHeadline, editFleetLabel);
}

function addColonyLabelEditIcon() {
	// fix headline html so we can add an edit icon
	const colonyName = colonyHeadline.textContent.trim();
	colonyHeadline.innerHTML = `<span id="pageHeadLine">${colonyName}</span>`;
	colonyHeadline = byId("pageHeadLine");
	// add an edit icon
	addLabelEditIcon(colonyHeadline, editColonyLabel);
}

// TEMPORARY: migrate if needed (from version 1.2.X)
function migrateFrom12() {
	function migrateKey(fromKey, toKey) {
		function convertMap(m) {
			Object.keys(m).forEach((key) => {
				// convert "label" to object with old and new name, and timestamp
				// note: old and new names will be equal to label for migrated data; it's a temporary anyway
				m[key] = {'l':m[key], 'n':m[key]};
			});
		}
		const labels = localStorage.getItem(fromKey);
		if (labels) {
			const m = labels ? JSON.parse(labels) : {};
			convertMap(m);
			localStorage.setItem(toKey, JSON.stringify(m));
			localStorage.removeItem(fromKey);
		}
	}
	migrateKey("abs.flabs", KEY_FLEET_LABELS);
	migrateKey("abs.clabs", KEY_COLONY_LABELS);
}

// migrate from older storage format if needed
migrateFrom12();

// show edit icon on fleet detail page title
if (fleetId && fleetHeadline) {
	addFleetLabelEditIcon();
}

// show edit icon on colony detail page title
if (colonyId && colonyHeadline) {
	addColonyLabelEditIcon();
}

// replace labels for fleets and/or colonies on the page
displayFleetLabels();
displayColonyLabels();