// ==UserScript==
// @author DanielOnDiordna
// @name Player Tracker add-on
// @category Addon
// @version 2.0.1.20251028.233800
// @updateURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/DanielOnDiordna/player-tracker-addon.meta.js
// @downloadURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/DanielOnDiordna/player-tracker-addon.user.js
// @description [danielondiordna-2.0.1.20251028.233800] Add-on to the player tracker plugin: Adjust history limit of 3 hours to another value. Toggle name labels, last action time, toggle/adjust player colors, focus on players, display 1 single player. Integrated Marker Label plugin and Spectrum Colorpicker 1.8.1 plugin. Supports Machina _̶̱̍_̴̳͉̆̈́M̷͔̤͒Ą̷̍C̴̼̕ͅH̶̹͕̼̾Ḭ̵̇̾̓N̵̺͕͒̀̍Ä̴̞̰́_̴̦̀͆̓_̷̣̈́ player.
// @id player-tracker-addon@DanielOnDiordna
// @namespace https://softspot.nl/ingress/
// @depends player-activity-tracker@breunigs
// @match https://intel.ingress.com/*
// @grant none
// ==/UserScript==
function wrapper(plugin_info) {
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};
// use own namespace for plugin
window.plugin.playerTrackerAddon = function() {};
var self = window.plugin.playerTrackerAddon;
self.id = 'playerTrackerAddon';
self.title = 'Player Tracker add-on';
self.version = '2.0.1.20251028.233800';
self.author = 'DanielOnDiordna';
self.changelog = `
Changelog:
version 2.0.1.20251028.233800
- fix drawData for Player tracker 0.14.0.20251027.080601 (part of IITC beta 0.41.0)
version 2.0.0.20250424.223800
- version 2 with a lot of changes to the inner workings of the plugin
- fix for Player Tracker version 0.14.0 and IITC 0.40.0
- add-on will now run right after Player Tracker setup to place the Machine layer chooser under the others
- Machina Unknown U̶͚̓̍N̴̖̈K̠͔̍͑̂͜N̞̥͋̀̉Ȯ̶̹͕̀W̶̢͚͑̚͝Ṉ̨̟̒̅' renamed to Machina _̶̱̍_̴̳͉̆̈́M̷͔̤͒Ą̷̍C̴̼̕ͅH̶̹͕̼̾Ḭ̵̇̾̓N̵̺͕͒̀̍Ä̴̞̰́_̴̦̀͆̓_̷̣̈́
version 1.3.1.20240209.233200
- minor fix to display player nickname on the labels (fix for Player Tracker version 0.12.3.20240201.073623 IITC-CE 0.37.1 beta)
version 1.3.0.20230514.005600
- added Machina U̶͚̓̍N̴̖̈K̠͔̍͑̂͜N̞̥͋̀̉Ȯ̶̹͕̀W̶̢͚͑̚͝Ṉ̨̟̒̅' icons, player tracker layer and colors
- reversed the changelog order to show last changes at the top
version 1.2.0.20220319.231800
- added new option to hide the "on your portal" actions, which can interfere when viewing remote locations
version 1.0.2.20211011.231300
- added new option to hide the date from the label if it is today, if show date+time is set
- properly replaced the playerTracker publicChatDataAvailable handleData hook
- fixed a console warning about a missing color during updateplayerlist when the menu is not visible
- reformatted the settings menu
version 1.0.1.20210724.002500
- prevent double plugin setup on hook iitcLoaded
version 1.0.1.20210421.190200
- minor fix for IITC CE where runHooks iitcLoaded is executed before addHook is defined in this plugin
version 1.0.1.20210328.000100
- added click event to player tracker icons while name labels are enabled to show history
- changed default settings values
version 1.0.0.20210119.225600
- changed description header
version 1.0.0.20210119.201900
- integrated marker label plugin code, no need anymore for the separate plugin
- integrated Spectrum Colorpicker 1.8.1 plugin code, no need anymore for the separate plugin
- updated plugin wrapper and userscript header formatting to match IITC-CE coding
version 0.0.13.20200131.220500
- problem solved, added better processNewData fix
version 0.0.12.20200130.172600
- problem solved, added processNewData fix
version 0.0.3.20200130.160000
version 0.0.4.20200130.160000
version 0.0.5.20200130.160000
version 0.0.6.20200130.160000
version 0.0.7.20200130.160000
version 0.0.8.20200130.160000
version 0.0.9.20200130.160000
version 0.0.10.20200130.160000
version 0.0.11.20200130.160000
- debugging for IITC CE purposes
version 0.0.2.20190915.135600
- fix for ago display for iOS users
- modified defaults for new users: show labels, apply random colors
- changed menu order and modified some menu labels to make it more clear
version 0.0.1.20181018.104200
- added plugin version on menu
- added option list to set maximum events to display (default 10)
- added choice to display date and time instead of default 'ago'
version 0.0.1.20181030.212900
- intel URL changed from www.ingress.com to *.ingress.com
`;
self.namespace = 'window.plugin.' + self.id + '.';
self.pluginname = 'plugin-' + self.id;
self.localstoragesettings = 'plugin-' + self.id + '-settings';
self.settings = {
limit: 3,
showlabels: true,
applyrandomcolors: true,
showcenter: false,
showlastaction: true,
maxdisplayevents: 10,
showdatetime: true,
hidedatetoday: false
};
// hideonyourportalactions: false
self.displayselectedplayer = false;
self.selectedplayer = '';
self.drawData_backup = '';
self.ago_backup = '';
let unknown = 'U̶͚̓̍N̴̖̈K̠͔̍͑̂͜N̞̥͋̀̉Ȯ̶̹͕̀W̶̢͚͑̚͝Ṉ̨̟̒̅';
let machina = '_̶̱̍_̴̳͉̆̈́M̷͔̤͒Ą̷̍C̴̼̕ͅH̶̹͕̼̾Ḭ̵̇̾̓N̵̺͕͒̀̍Ä̴̞̰́_̴̦̀͆̓_̷̣̈́';
self.restoresettings = function() {
if (!Object.keys(localStorage).includes(self.localstoragesettings) || localStorage.getItem(self.localstoragesettings) == '') return;
function isObject(element) {
return (typeof element == 'object' && element instanceof Object && !(element instanceof Array));
}
function parseSettings(source,target) {
if (!isObject(source) || !isObject(target)) return;
for (const key in target) {
if (key in source) {
if (isObject(target[key])) {
parseSettings(source[key],target[key]);
} else if (typeof source[key] == typeof target[key]) { // only accept settings from default settings template of same type
target[key] = source[key];
}
}
}
}
try {
let settings = JSON.parse(localStorage.getItem(self.localstoragesettings));
parseSettings(settings,self.settings);
// convert old settings here if needed
let storechanges = false;
if (Object.keys(localStorage).includes('plugin-playerTrackerOverride-limit')) {
self.settings.limit = parseFloat(localStorage.getItem('plugin-playerTrackerOverride-limit'));
localStorage.removeItem('plugin-playerTrackerOverride-limit');
storechanges = true;
}
if (Object.keys(localStorage).includes('plugin-playerTrackerOverride-showlabels')) {
self.settings.showlabels = localStorage.getItem('plugin-playerTrackerOverride-showlabels') === '1';
localStorage.removeItem('plugin-playerTrackerOverride-showlabels');
storechanges = true;
}
if (Object.keys(localStorage).includes('plugin-playerTrackerOverride-color')) {
self.settings.applyrandomcolors = localStorage.getItem('plugin-playerTrackerOverride-color') === '1';
localStorage.removeItem('plugin-playerTrackerOverride-color');
storechanges = true;
}
if (!self.settings.limit) { // set a default if missing or zero
self.settings.limit = window.PLAYER_TRACKER_MAX_TIME / (60*60*1000);
storechanges = true;
}
if (storechanges) {
self.storesettings();
}
} catch(e) {
console.log(`${self.title} - Failed to restore localStorage settings`,e);
return false;
}
};
self.storesettings = function() {
try {
localStorage.setItem(self.localstoragesettings,JSON.stringify(self.settings));
} catch(e) {
console.warn(`${self.title} - Failed to store localStorage settings`,e);
}
};
self.setlimit = function(hours) {
hours = parseFloat(hours);
self.settings.limit = hours;
self.storesettings();
window.PLAYER_TRACKER_MAX_TIME = hours * 60*60*1000;
window.plugin.playerTracker.handleData(); // call to processNewData requires data, this is fixed by rewriting that function elsewhere
};
self.setmaxdisplayevents = function(max) {
max = parseInt(max);
self.settings.maxdisplayevents = max;
self.storesettings();
self.resettracks();
};
self.labelsetup = function() {
// documentation: https://github.com/jacobtoye/Leaflet.iconlabel
// create a label for each marker, override the original code:
// optional:
// iconSize: new L.Point(24, 24),
// labelClassName: 'custom-label-formatting-class',
if (!window.plugin.playerTracker.iconEnl) return; // playerTracker setup is not ready yet
self.iconLabelEnl = window.L.Icon.Label.extend({
options: {
iconUrl: window.plugin.playerTracker.iconEnl.prototype.options.iconUrl,
iconRetinaUrl: window.plugin.playerTracker.iconEnl.prototype.options.iconRetinaUrl,
shadowUrl: null,
iconSize: new window.L.Point(25, 41),
iconAnchor: new window.L.Point(0, -28),
labelAnchor: new window.L.Point(16, -18),
wrapperAnchor: new window.L.Point(12, 13)
}
});
self.iconLabelRes = window.L.Icon.Label.extend({
options: {
iconUrl: window.plugin.playerTracker.iconRes.prototype.options.iconUrl,
iconRetinaUrl: window.plugin.playerTracker.iconRes.prototype.options.iconRetinaUrl,
shadowUrl: null,
iconSize: new window.L.Point(25, 41),
iconAnchor: new window.L.Point(0, -28),
labelAnchor: new window.L.Point(16, -18),
wrapperAnchor: new window.L.Point(12, 13)
}
});
self.iconLabelMac = window.L.Icon.Label.extend({
options: {
iconUrl: window.plugin.playerTracker.iconMac.prototype.options.iconUrl,
iconRetinaUrl: window.plugin.playerTracker.iconMac.prototype.options.iconRetinaUrl,
shadowUrl: null,
iconSize: new window.L.Point(25, 41),
iconAnchor: new window.L.Point(0, -28),
labelAnchor: new window.L.Point(16, -18),
wrapperAnchor: new window.L.Point(12, 13)
}
});
};
function replaceText(source,search,replace) {
let result = source.replace(search,replace);
if (result == source) console.warn(`${self.title} - ${(new Error()).stack?.split("\n")[2]?.trim().split(" ")[1]} replaceText failed: ${search}`);
return result;
}
function functionExists(functionname) {
let functionexists = false;
try {
functionexists = typeof(eval(functionname)) == 'function';
} catch(e) {
functionexists = false;
}
return functionexists;
}
function replaceFunction(functionname,functiontext) {
if (!functionExists(functionname)) {
console.warn(`${self.title} - ${(new Error()).stack?.split("\n")[2]?.trim().split(" ")[1]} function does not exist: ${functionname}`);
return;
}
try {
eval(`${functionname} = ${functiontext}`);
} catch(e) {
console.warn(`${self.title} - ${(new Error()).stack?.split("\n")[2]?.trim().split(" ")[1]} replace function failed: ${functionname}`,e,functiontext);
}
}
self.modify_processNewData = function() {
if (!functionExists('window.plugin.playerTracker.processNewData')) return;
let processNewData_override = window.plugin.playerTracker.processNewData.toString();
// prevent errors with invalid data argument
processNewData_override = replaceText(processNewData_override,/( +)(var limit)/,'$1if (!data) return;\n$1$2');
// add color to all stored players
processNewData_override = replaceText(processNewData_override,/( +)(events: \[newEvent\])/,`$1$2,\n$1color: ${self.namespace}settings.applyrandomcolors ? ${self.namespace}getRandomTeamColor(plrname,json[2].plext.team) : window.PLAYER_TRACKER_LINE_COLOUR`);
// add variable action:
processNewData_override = replaceText(processNewData_override,/( address);/,'$1, action;');
// fill action with value markup[1].plain:
processNewData_override = replaceText(processNewData_override,/( +)(case 'TEXT':)/,'$1$2\n$1 action = markup[1].plain;');
// fill actions with array
processNewData_override = replaceText(processNewData_override,/( +)(address: address)/,'$1$2,\n$1actions: [action]');
// remove team check, to include machina/neutral
processNewData_override = replaceText(processNewData_override,/ \|\| !\[window\.TEAM_RES.*\) {/,') {');
replaceFunction('window.plugin.playerTracker.processNewData',processNewData_override);
};
self.resettracks = function() {
if (!window.plugin.playerTracker.drawnTracesEnl) return;
window.plugin.playerTracker.drawnTracesEnl.clearLayers();
window.plugin.playerTracker.drawnTracesRes.clearLayers();
window.plugin.playerTracker.drawnTracesMac.clearLayers();
window.plugin.playerTracker.drawData();
};
self.modify_drawData = function() {
if (!functionExists('window.plugin.playerTracker.drawData')) return;
if (!self.drawData_backup) {
self.drawData_backup = window.plugin.playerTracker.drawData.toString();
}
let drawData_override = self.drawData_backup;
if (drawData_override.search(/var polyLineByAgeRes/) >= 0) {
// pre 0.40.0, add polyLineByAgeMac
drawData_override = replaceText(drawData_override,/(var polyLineByAgeRes.*?\n)/s,'$1var polyLineByAgeMac = {};\n');
drawData_override = replaceText(drawData_override,/(else\n)/s,'else if(playerData.team === \'NEUTRAL\')\n { if (!polyLineByAgeMac[plrname]) polyLineByAgeMac[plrname] = [[], [], [], []]; polyLineByAgeMac[plrname][ageBucket].push(line); }\n $1');
}
// add class for Machina
drawData_override = replaceText(drawData_override,/(addClass\('nickname.*?)('enl')/,`$1(playerData.team === 'NEUTRAL' ? 'mac' : $2)`);
// add Machina icon
drawData_override = replaceText(drawData_override,/(var icon =.*?) : (.*?);/s,`$1 : (playerData.team === 'NEUTRAL' ? new window.plugin.playerTracker.iconMac() : $2);`);
if (functionExists('window.plugin.playerTracker.getDrawnTracesByTeam')) {
let getDrawnTracesByTeam_string = window.plugin.playerTracker.getDrawnTracesByTeam.toString();
// 0.40.0: return team === 'RESISTANCE' ? window.plugin.playerTracker.drawnTracesRes : window.plugin.playerTracker.drawnTracesEnl;
getDrawnTracesByTeam_string = replaceText(getDrawnTracesByTeam_string,/(return .*?) : (.*?);/,'$1 : (team === \'NEUTRAL\' ? plugin.playerTracker.drawnTracesMac : $2);');
replaceFunction('window.plugin.playerTracker.getDrawnTracesByTeam',getDrawnTracesByTeam_string);
} else {
// 0.39.1: m.addTo(playerData.team === 'RESISTANCE' ? plugin.playerTracker.drawnTracesRes : plugin.playerTracker.drawnTracesEnl);
drawData_override = replaceText(drawData_override,/(m.addTo\(.*?) : (.*?);/s,'$1 : (playerData.team === \'NEUTRAL\' ? plugin.playerTracker.drawnTracesMac : $2);');
}
if (drawData_override.search(/var polyLineByAgeRes/) >= 0) {
// pre 0.40.0, add polyLineByAgeMac
drawData_override = replaceText(drawData_override,/\}$/s,`
$.each(polyLineByAgeMac, function(plrname, polyLineByAge) {
$.each(polyLineByAge, function(i, polyLine) {
if(polyLine.length === 0) return true;
var opts = {
weight: 2-0.25*i,
color: window.plugin.playerTracker.stored[plrname].color,
interactive: false,
opacity: 1-0.2*i,
dashArray: "5,8"
};
$.each(polyLine, function(ind,poly) {
L.polyline(poly, opts).addTo(plugin.playerTracker.drawnTracesMac);
});
});
});
//console.log('NEUTRAL PLAYER INJECTED');
}`);
}
// add icons with labels
drawData_override = replaceText(drawData_override,/(new .*?icon)(Enl|Res|Mac)(\(\))/g,`(${self.namespace}settings.showlabels ? new ${self.namespace}iconLabel$2({ labelText: (plrname || playerData.nick) + (${self.namespace}settings.showlastaction?', ' + ${self.namespace}ago(playerData.events[playerData.events.length - 1].time,now):'') }) : $1$2$3)`);
drawData_override = replaceText(drawData_override,/( +)(if\s*\(!playerData)/,`$1if (${self.namespace}displayselectedplayer && plrname !== ${self.namespace}selectedplayer) return true;\n$1$2`);
if (drawData_override.match(/var polyLineByAgeEnl = \[/)) {
// pre 0.40.0:
drawData_override = replaceText(drawData_override,'var polyLineByAgeEnl = ','var polyLineByAgeEnl = {}; //');
drawData_override = replaceText(drawData_override,'var polyLineByAgeRes = ','var polyLineByAgeRes = {}; //');
drawData_override = replaceText(drawData_override,'polyLineByAgeRes[ageBucket].push(line);','{ if (!polyLineByAgeRes[plrname]) polyLineByAgeRes[plrname] = [[], [], [], []]; polyLineByAgeRes[plrname][ageBucket].push(line); }');
drawData_override = replaceText(drawData_override,'polyLineByAgeEnl[ageBucket].push(line);','{ if (!polyLineByAgeEnl[plrname]) polyLineByAgeEnl[plrname] = [[], [], [], []]; polyLineByAgeEnl[plrname][ageBucket].push(line); }');
drawData_override = replaceText(drawData_override,'$.each(polyLineByAgeEnl, function(i, polyLine) {','$.each(polyLineByAgeEnl, function(plrname, polyLineByAge) {\n$.each(polyLineByAge, function(i, polyLine) {');
drawData_override = replaceText(drawData_override,'color: PLAYER_TRACKER_LINE_COLOUR,','color: window.plugin.playerTracker.stored[plrname].color,');
drawData_override = replaceText(drawData_override,'$.each(polyLineByAgeRes, function(i, polyLine) {','});\n$.each(polyLineByAgeRes, function(plrname, polyLineByAge) {\n$.each(polyLineByAge, function(i, polyLine) {');
drawData_override = replaceText(drawData_override,'color: PLAYER_TRACKER_LINE_COLOUR,','color: window.plugin.playerTracker.stored[plrname].color,');
drawData_override = drawData_override + ');}';
} else {
// from 0.40.0:
drawData_override = replaceText(drawData_override,'color: window.PLAYER_TRACKER_LINE_COLOUR,','color: window.plugin.playerTracker.stored[playerName].color,');
}
// 0.39.1: for(var i = evtsLength - 2; i >= 0 && i >= evtsLength - 10; i--) {
// 0.40.0: for (let i = evtsLength - 2; i >= 0 && i >= evtsLength - window.PLAYER_TRACKER_MAX_DISPLAY_EVENTS; i--) {
drawData_override = replaceText(drawData_override,/(for\s*\()(var|let)( i = evtsLength - 2; i >= 0 && i >= evtsLength - )(10|window\.PLAYER_TRACKER_MAX_DISPLAY_EVENTS)(; i--\) \{)/,'$1$2$3' + self.namespace + 'settings.maxdisplayevents$5');
drawData_override = replaceText(drawData_override,/ ago = (plugin\.playerTracker\.ago|IITC\.utils\.formatAgo);/,` ago = ${self.namespace}ago;`);
drawData_override = replaceText(drawData_override,/(' ago')/g,`(${self.namespace}settings.showdatetime?'':$1)`);
// 0.39.1: var m = L.marker(gllfe(last), { icon: icon, opacity: absOpacity, desc: popup[0], title: tooltip });
// 0.40.0: const markerPos = gllfe(last);
// var m = L.marker(markerPos, { icon: icon, opacity: absOpacity, desc: popup[0], title: tooltip });
// 0.14.0 beta:
// var m = new L.Marker(markerPos, { icon: icon, opacity: absOpacity, desc: popup[0], title: tooltip });
if (drawData_override.match(/const markerPos/)) drawData_override = replaceText(drawData_override,/ +const markerPos = gllfe\(last\);\n/,'');
drawData_override = replaceText(drawData_override,/( +)(var m = )(new |)(L\.[mM]arker)/,`
$1let markerPos = gllfe(last);
$1if (${self.namespace}settings.showcenter) {
$1$1let screen = window.map.getBounds();
$1$1if (screen.contains(markerPos)) markerPos = window.L.latLng(screen._southWest.lat + (screen._northEast.lat - screen._southWest.lat)/2,screen._southWest.lng + (screen._northEast.lng - screen._southWest.lng)/2);
$1}
$1$2$3$4`);
replaceFunction('window.plugin.playerTracker.drawData',drawData_override);
};
self.modify_ago = function() {
if (functionExists('window.plugin.playerTracker.ago')) {
window.plugin.playerTracker.ago = self.ago;
return;
}
/*
if (!self.ago_backup) {
self.ago_backup = window.plugin.playerTracker.ago.toString();
}
let ago_override = self.ago_backup;
if (ago_override.match(/var returnVal = m/)) {
if (ago_override.match(/function\(time, now\) \{/)) {
ago_override = replaceText(ago_override,/(function\(time, now\) \{\n)( +)/,`$1$2if (${self.namespace}settings.showdatetime) {\n$2$2if (!(time instanceof Date)) {\n$2$2$2if (time) {\n$2$2$2$2time = new Date(time);\n$2$2$2} else {\n$2$2$2$2time = new Date();\n$2$2$2}\n$2$2}\n$2$2return (${self.namespace}settings.hidedatetoday && new Date().toDateString() == time.toDateString()?"":[time.getFullYear(),time.getMonth()+1,time.getDate()].join('-') + ' ') + [time.getHours(),('0' + time.getMinutes()).slice(-2)].join(':');\n$2}\n$2`);
} else if (ago_override.match(/function \(time, now\) \{/)) { // fix for IITC on iOS
ago_override = replaceText(ago_override,/(function \(time, now\) \{\n)( +)/,`$1$2if (${self.namespace}settings.showdatetime) {\n$2$2if (!(time instanceof Date)) {\n$2$2$2if (time) {\n$2$2$2$2time = new Date(time);\n$2$2$2} else {\n$2$2$2$2time = new Date();\n$2$2$2}\n$2$2}\n$2$2return (${self.namespace}settings.hidedatetoday && new Date().toDateString() == time.toDateString()?"":[time.getFullYear(),time.getMonth()+1,time.getDate()].join('-') + ' ') + [time.getHours(),('0' + time.getMinutes()).slice(-2)].join(':');\n$2}\n$2`);
}
}
replaceFunction('window.plugin.playerTracker.ago',ago_override);
*/
};
self.getRandomTeamColor = function(plrname,team) {
// return '#' + (Math.random().toString(16) + '00000000').slice(2, 8).toUpperCase();
if (!plrname) plrname = '';
let hash = 0;
for (let i = 0; i < plrname.length; i++) {
hash = plrname.charCodeAt(i) + ((hash << 5) - hash);
}
hash = Math.abs(hash);
hash %= 200;
hash += 55; // result: number from 55 to 255
let randomcolor = hash.toString(16).toUpperCase();
if (team === 'ENLIGHTENED') {
// random green color
return '#00' + randomcolor + '00';
} else if (team === 'RESISTANCE') {
// random blue color
return '#0000' + randomcolor;
} else if (team === 'NEUTRAL') {
// random red color
return '#' + randomcolor + '0000';
}
return '#' + (hash.toString(16) + '00000000').slice(2, 8).toUpperCase();
};
self.showlist = function() {
if (!window.plugin.playerTracker.stored) return;
let resultsE = [];
let resultsR = [];
let resultsU = [];
for (const [plrname, player] of Object.entries(window.plugin.playerTracker.stored)) {
let text = `${plrname} ${self.ago(player.events[player.events.length-1].time, new Date().getTime())}${self.settings.showdatetime ? '' : ' ago'}${player.events.length > 1 ? ` (${player.events.length} events)`:''}`;
if (player.team === "ENLIGHTENED") {
resultsE.push(text);
} else if (player.team === "NEUTRAL") {
resultsU.push(text);
} else {
resultsR.push(text);
}
}
alert('ENLIGHTENED:\n' + resultsE.sort(function(a,b) { return (a.toLowerCase() < b.toLowerCase()?-1:(a.toLowerCase() > b.toLowerCase()?1:0)); }).join('\n') + '\n' +
'\nRESISTANCE:\n' + resultsR.sort(function(a,b) { return (a.toLowerCase() < b.toLowerCase()?-1:(a.toLowerCase() > b.toLowerCase()?1:0)); }).join('\n') + '\n' +
`\n${machina}:\n` + resultsU.sort(function(a,b) { return (a.toLowerCase() < b.toLowerCase()?-1:(a.toLowerCase() > b.toLowerCase()?1:0)); }).join('\n'));
};
self.setSelectedPlayerColor = function(color) {
if (!self.selectedplayer || !window.plugin.playerTracker?.stored[self.selectedplayer]) return;
window.plugin.playerTracker.stored[self.selectedplayer].color = color;
let playerselectlist_select = document.querySelector(`select[name=${self.id}_playerselectlist]`);
if (playerselectlist_select) {
playerselectlist_select.style.color = color;
playerselectlist_select.options[playerselectlist_select.options.selectedIndex].style.color = color;
}
self.resettracks();
};
self.updateplayerlist = function(playerselectlist_select,input_playercolor) {
if (!playerselectlist_select) playerselectlist_select = document.querySelector(`select[name=${self.id}_playerselectlist]`);
if (!input_playercolor) input_playercolor = document.querySelector(`input[name=${self.id}_playercolor]`);
if (!playerselectlist_select || !input_playercolor) return;
while (playerselectlist_select.options.length) { // remove all options
playerselectlist_select.options.remove(0);
}
if (!Object.keys(window.plugin.playerTracker?.stored || {}).length) {
let option = playerselectlist_select.appendChild(document.createElement('option'));
option.text = 'no players found';
self.selectedplayer = undefined;
playerselectlist_select.style.color = 'black';
$(input_playercolor).spectrum('set','black');
} else {
Object.keys(window.plugin.playerTracker?.stored).sort(function(a,b) { return (a.toLowerCase() < b.toLowerCase()?-1:(a.toLowerCase() > b.toLowerCase()?1:0)); }).forEach(plrname => {
let option = playerselectlist_select.appendChild(document.createElement('option'));
option.value = plrname;
option.text = `${plrname} ${window.plugin.playerTracker?.stored[plrname]?.team || ''}`;
option.style.color = window.plugin.playerTracker.stored[plrname]?.color || window.PLAYER_TRACKER_LINE_COLOUR;
if (!self.selectedplayer) self.selectedplayer = plrname;
if (plrname == self.selectedplayer) {
option.selected = true;
playerselectlist_select.style.color = option.style.color;
$(input_playercolor).spectrum('set',option.style.color);
}
});
}
};
self.viewselectedplayer = function() {
let plyrname = self.selectedplayer;
if (!plyrname || !window.plugin.playerTracker?.stored[plyrname]?.events) return;
let lasteventlatlng = window.plugin.playerTracker.stored[plyrname].events[window.plugin.playerTracker.stored[plyrname].events.length-1].latlngs[0];
// map.fitBounds(window.plugin.quickdrawlinks.drawnItems.getBounds());
let position = new window.L.LatLng(lasteventlatlng[0],lasteventlatlng[1]);
window.map.setView(position, window.map.getZoom());
};
self.menu = function() {
let limitchoices = {'30 minutes':0.5,'1 hour':1,'2 hours':2,'3 hours (default)':3,'4 hours':4,'5 hours':5,'6 hours':6,'12 hours':12,'1 day':24,'2 days':48,'3 days':72,'4 days':96,'5 days':120,'6 days':144,'1 week':168};
let maxdisplayeventschoices = {'1':1,'5':5,'10 (default)':10,'15':15,'20':20,'25':25,'30':30,'40':40};
let container = document.createElement('div');
container.className = `${self.id}menu`;
container.innerHTML = `
Show player name labels
Display time on labels
Show date+time instead of 'ago'
Hide date if it is today
Event history:
History lines:
Center all visible players on the map
Adjust color for selected player:
Apply random team colors
Display selected player only
Focus on selected player
Show list of stored players
${self.title} version ${self.version} by ${self.author}
`;
let showlabels = container.querySelector(`input[name=${self.id}_showlabels]`);
showlabels.checked = self.settings.showlabels;
let showlastaction = container.querySelector(`input[name=${self.id}_showlastaction]`);
showlastaction.checked = self.settings.showlastaction;
showlastaction.disabled = !self.settings.showlabels;
let showdatetime = container.querySelector(`input[name=${self.id}_showdatetime]`);
showdatetime.checked = self.settings.showdatetime;
//showdatetime.disabled = !(self.settings.showlabels && self.settings.showlastaction);
let hidedatetoday = container.querySelector(`input[name=${self.id}_hidedatetoday]`);
hidedatetoday.checked = self.settings.hidedatetoday;
hidedatetoday.disabled = !self.settings.showdatetime; //!(self.settings.showlabels && self.settings.showlastaction && self.settings.showdatetime);
// Hide "on your portal" actions
// let hideonyourportalactions = container.querySelector(`input[name=${self.id}_hideonyourportalactions]`);
// hideonyourportalactions.checked = self.settings.hideonyourportalactions;
function applySettings() {
window.map.closePopup(window.plugin.playerTracker.playerPopup);
self.resettracks();
showlastaction.disabled = !self.settings.showlabels;
//showdatetime.disabled = !(self.settings.showlabels && self.settings.showlastaction);
hidedatetoday.disabled = !self.settings.showdatetime; //!(self.settings.showlabels && self.settings.showlastaction && self.settings.showdatetime);
}
showlabels.addEventListener('change', function(e) {
e.preventDefault();
self.settings.showlabels = this.checked;
self.storesettings();
applySettings();
},false);
showlastaction.addEventListener('change', function(e) {
e.preventDefault();
self.settings.showlastaction = this.checked;
self.storesettings();
applySettings();
},false);
showdatetime.addEventListener('change', function(e) {
e.preventDefault();
self.settings.showdatetime = this.checked;
self.storesettings();
applySettings();
},false);
hidedatetoday.addEventListener('change', function(e) {
e.preventDefault();
self.settings.hidedatetoday = this.checked;
self.storesettings();
applySettings();
},false);
/*
hideonyourportalactions.addEventListener('change', function(e) {
e.preventDefault();
self.settings.hideonyourportalactions = this.checked;
self.storesettings();
self.resettracks();
},false);
*/
let history_select = container.querySelector(`select[name=${self.id}_history]`);
for (let key of Object.keys(limitchoices).sort(function(a, b) {return -(limitchoices[b] - limitchoices[a])})) {
let option = history_select.appendChild(document.createElement('option'));
option.value = limitchoices[key].toString();
option.text = key;
if (limitchoices[key] == self.settings.limit) option.selected = true;
}
history_select.addEventListener('change', function(e) {
e.preventDefault();
self.setlimit(this.value);
},false);
let historylines_select = container.querySelector(`select[name=${self.id}_historylines]`);
for (let key of Object.keys(maxdisplayeventschoices).sort(function(a, b) {return -(maxdisplayeventschoices[b] - maxdisplayeventschoices[a])})) {
let option = historylines_select.appendChild(document.createElement('option'));
option.value = maxdisplayeventschoices[key].toString();
option.text = key;
if (maxdisplayeventschoices[key] == self.settings.maxdisplayevents) option.selected = true;
}
let showcenter_checkbox = container.querySelector(`input[name=${self.id}_showcenter]`);
showcenter_checkbox.checked = self.settings.showcenter;
showcenter_checkbox.addEventListener('change', function(e) {
e.preventDefault();
self.settings.showcenter = this.checked;
self.storesettings();
self.resettracks();
},false);
// need to initialise the 'spectrum' color picker
let input_playercolor = container.querySelector(`input[name=${self.id}_playercolor]`);
$(input_playercolor).spectrum({
flat: false,
showInput: true,
showButtons: true,
showPalette: true,
showSelectionPalette: true,
allowEmpty: false,
palette: [
['#004000','#008000','#00C000'],
['#00FF00','#80FF80','#C0FFC0'],
['#000040','#000080','#0000C0'],
['#4040FF','#8080FF','#C0C0FF'],
['#6A3400','#964A00','#C05F00'],
['#E27000','#FF8309','#FFC287',window.PLAYER_TRACKER_LINE_COLOUR],
['#a24ac3','#514ac3','#4aa8c3','#51c34a'],
['#c1c34a','#c38a4a','#c34a4a','#c34a6f'],
['#000000','#666666','#bbbbbb','#ffffff']
],
change: function(color) { self.setSelectedPlayerColor(color.toHexString()); }
});
let playerselectlist_select = container.querySelector(`select[name=${self.id}_playerselectlist]`);
self.updateplayerlist(playerselectlist_select,input_playercolor);
playerselectlist_select.addEventListener('change', function(e) {
e.preventDefault();
self.selectedplayer = this.value;
if (self.displayselectedplayer) self.resettracks();
this.style.color = this.options[this.options.selectedIndex].style.color;
$(input_playercolor).spectrum('set',this.style.color);
},false);
let randomcolor_checkbox = container.querySelector(`input[name=${self.id}_randomcolor]`);
randomcolor_checkbox.checked = self.settings.applyrandomcolors;
randomcolor_checkbox.addEventListener('change', function(e) {
e.preventDefault();
self.settings.applyrandomcolors = this.checked;
for (let [plrname, player] of Object.entries(window.plugin.playerTracker.stored)) {
player.color = self.settings.applyrandomcolors ? self.getRandomTeamColor(plrname,player.team) : window.PLAYER_TRACKER_LINE_COLOUR;
}
self.storesettings();
self.updateplayerlist(playerselectlist_select,input_playercolor);
self.resettracks();
},false);
let selectedplayer_checkbox = container.querySelector(`input[name=${self.id}_selectedplayer]`);
selectedplayer_checkbox.checked = self.displayselectedplayer;
selectedplayer_checkbox.addEventListener('change', function(e) {
e.preventDefault();
self.displayselectedplayer = this.checked;
self.resettracks();
},false);
let focus_button = container.querySelector(`a[name=${self.id}_focus]`);
focus_button.addEventListener('click', function(e) {
e.preventDefault();
self.viewselectedplayer();
},false);
let showlist_button = container.querySelector(`a[name=${self.id}_showlist]`);
showlist_button.addEventListener('click', function(e) {
e.preventDefault();
self.showlist();
},false);
window.dialog({
id: `ui-dialog-${self.id}`,
html: container,
title: self.title
}).dialog('option', 'buttons', {
'Changelog': function() { alert(self.changelog); },
'Close': function() { $(this).dialog('close'); }
});
};
self.setupMarkerlabel = function() {
/*
Leaflet.iconlabel (https://github.com/jacobtoye/Leaflet.iconlabel) Copyright 2012 Jacob Toye
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
L.Icon.Label = L.Icon.extend({
options: {
/*
labelAnchor: (Point) (top left position of the label within the wrapper, default is right)
wrapperAnchor: (Point) (position of icon and label relative to Lat/Lng)
iconAnchor: (Point) (top left position of icon within wrapper)
labelText: (String) (label's text component, if this is null the element will not be created)
*/
/* Icon options:
iconUrl: (String) (required)
iconSize: (Point) (can be set through CSS)
iconAnchor: (Point) (centered by default if size is specified, can be set in CSS with negative margins)
popupAnchor: (Point) (if not specified, popup opens in the anchor point)
shadowUrl: (Point) (no shadow by default)
shadowSize: (Point)
*/
labelClassName: ''
},
initialize: function (options) {
L.Util.setOptions(this, options);
L.Icon.prototype.initialize.call(this, this.options);
},
setLabelAsHidden: function () {
this._labelHidden = true;
},
createIcon: function () {
return this._createLabel(L.Icon.prototype.createIcon.call(this));
},
createShadow: function () {
if (!this.options.shadowUrl) {
return null;
}
var shadow = L.Icon.prototype.createShadow.call(this);
//need to reposition the shadow
if (shadow) {
shadow.style.marginLeft = (-this.options.wrapperAnchor.x) + 'px';
shadow.style.marginTop = (-this.options.wrapperAnchor.y) + 'px';
}
return shadow;
},
updateLabel: function (icon, text) {
if (icon.nodeName.toUpperCase() === 'DIV') {
icon.childNodes[1].innerHTML = text;
this.options.labelText = text;
}
},
showLabel: function (icon) {
if (!this._labelTextIsSet()) {
return;
}
icon.childNodes[1].style.display = 'block';
},
hideLabel: function (icon) {
if (!this._labelTextIsSet()) {
return;
}
icon.childNodes[1].style.display = 'none';
},
_createLabel: function (img) {
if (!this._labelTextIsSet()) {
return img;
}
var wrapper = document.createElement('div'),
label = document.createElement('span');
// set up wrapper anchor
wrapper.style.marginLeft = (-this.options.wrapperAnchor.x) + 'px';
wrapper.style.marginTop = (-this.options.wrapperAnchor.y) + 'px';
wrapper.className = 'leaflet-marker-icon-wrapper leaflet-zoom-animated';
// set up label
label.className = 'leaflet-marker-iconlabel ' + this.options.labelClassName;
label.innerHTML = this.options.labelText;
label.style.marginLeft = this.options.labelAnchor.x + 'px';
label.style.marginTop = this.options.labelAnchor.y + 'px';
if (this._labelHidden) {
label.style.display = 'none';
// Ensure that the pointer cursor shows
img.style.cursor = 'pointer';
}
img.className = 'leaflet-interactive';
//reset icons margins (as super makes them -ve)
img.style.marginLeft = this.options.iconAnchor.x + 'px';
img.style.marginTop = this.options.iconAnchor.y + 'px';
wrapper.appendChild(img);
wrapper.appendChild(label);
return wrapper;
},
_labelTextIsSet: function () {
return typeof this.options.labelText !== 'undefined' && this.options.labelText !== null;
}
});
L.Icon.Label.Default = L.Icon.Label.extend({
options: {
//This is the top left position of the label within the wrapper. By default it will display at the right
//middle position of the default icon. x = width of icon + padding
//If the icon height is greater than the label height you will need to set the y value.
//y = (icon height - label height) / 2
labelAnchor: new L.Point(29, 8),
//This is the position of the wrapper div. Use this to position icon + label relative to the Lat/Lng.
//By default the point of the default icon is anchor
wrapperAnchor: new L.Point(13, 41),
//This is now the top left position of the icon within the wrapper.
//If the label height is greater than the icon you will need to set the y value.
//y = (label height - icon height) / 2
iconAnchor: new L.Point(0, 0),
//label's text component, if this is null the element will not be created
labelText: null,
/* From L.Icon.Default */
iconUrl: L.Icon.Default.imagePath + '/marker-icon.png',
iconSize: new L.Point(25, 41),
popupAnchor: new L.Point(0, -33),
shadowUrl: L.Icon.Default.imagePath + '/marker-shadow.png',
shadowSize: new L.Point(41, 41)
}
});
L.Marker.Label = L.Marker.extend({
updateLabel: function (text) {
this.options.icon.updateLabel(this._icon, text);
},
_initIcon: function () {
if (!(this.options.icon instanceof L.Icon.Label)) {
throw new Error('Icon must be an instance of L.Icon.Label.');
}
// Ensure that the label is hidden to begin with
if (this.options.revealing) {
this.options.icon.setLabelAsHidden();
}
L.Marker.prototype._initIcon.call(this);
},
_removeIcon: function () {
if (this.options.revealing) {
L.DomEvent
.off(this._icon, 'mouseover', this._showLabel)
.off(this._icon, 'mouseout', this._hideLabel);
}
L.Marker.prototype._removeIcon.call(this);
},
_initInteraction: function () {
L.Marker.prototype._initInteraction.call(this);
if (!this.options.revealing) {
return;
}
L.DomEvent
.on(this._icon, 'mouseover', this._showLabel, this)
.on(this._icon, 'mouseout', this._hideLabel, this);
},
_showLabel: function () {
this.options.icon.showLabel(this._icon);
},
_hideLabel: function () {
this.options.icon.hideLabel(this._icon);
}
});
// ' font: 9px/0.5 Arial;' +
// ' font: 12px/1.5 Arial;' +
$('head').append(
'');
}; // end self.setupMarkerlabel
self.setupColorpickerSpectrum = function() {
// source: https://github.com/bgrins/spectrum
// minified with https://www.minifier.org/
// Spectrum Colorpicker v1.8.1
// https://github.com/bgrins/spectrum
// Author: Brian Grinstead
// License: MIT
(function(factory){"use strict";if(typeof define==='function'&&define.amd){define(['jquery'],factory)}else if(typeof exports=="object"&&typeof module=="object"){module.exports=factory(require('jquery'))}else{factory(jQuery)}})(function($,undefined){"use strict";var defaultOpts={beforeShow:noop,move:noop,change:noop,show:noop,hide:noop,color:!1,flat:!1,showInput:!1,allowEmpty:!1,showButtons:!0,clickoutFiresChange:!0,showInitial:!1,showPalette:!1,showPaletteOnly:!1,hideAfterPaletteSelect:!1,togglePaletteOnly:!1,showSelectionPalette:!0,localStorageKey:!1,appendTo:"body",maxSelectionSize:7,cancelText:"cancel",chooseText:"choose",togglePaletteMoreText:"more",togglePaletteLessText:"less",clearText:"Clear Color Selection",noColorSelectedText:"No Color Selected",preferredFormat:!1,className:"",containerClassName:"",replacerClassName:"",showAlpha:!1,theme:"sp-light",palette:[["#ffffff","#000000","#ff0000","#ff8000","#ffff00","#008000","#0000ff","#4b0082","#9400d3"]],selectionPalette:[],disabled:!1,offset:null},spectrums=[],IE=!!/msie/i.exec(window.navigator.userAgent),rgbaSupport=(function(){function contains(str,substr){return!!~(''+str).indexOf(substr)}
var elem=document.createElement('div');var style=elem.style;style.cssText='background-color:rgba(0,0,0,.5)';return contains(style.backgroundColor,'rgba')||contains(style.backgroundColor,'hsla')})(),replaceInput=[""].join(''),markup=(function(){var gradientFix="";if(IE){for(var i=1;i<=6;i++){gradientFix+="
"}}
return[""].join("")})();function paletteTemplate(p,color,className,opts){var html=[];for(var i=0;i ')}else{var cls='sp-clear-display';html.push($('
').append($(' ').attr('title',opts.noColorSelectedText)).html())}}
return""+html.join('')+"
"}
function hideAll(){for(var i=0;iMath.abs(dragY-oldDragY);shiftMovementDirection=furtherFromX?"x":"y"}
var setSaturation=!shiftMovementDirection||shiftMovementDirection==="x";var setValue=!shiftMovementDirection||shiftMovementDirection==="y";if(setSaturation){currentSaturation=parseFloat(dragX/dragWidth)}
if(setValue){currentValue=parseFloat((dragHeight-dragY)/dragHeight)}
isEmpty=!1;if(!opts.showAlpha){currentAlpha=1}
move()},dragStart,dragStop);if(!!initialColor){set(initialColor);updateUI();currentPreferredFormat=opts.preferredFormat||tinycolor(initialColor).format;addColorToSelectionPalette(initialColor)}else{updateUI()}
if(flat){show()}
function paletteElementClick(e){if(e.data&&e.data.ignore){set($(e.target).closest(".sp-thumb-el").data("color"));move()}else{set($(e.target).closest(".sp-thumb-el").data("color"));move();if(opts.hideAfterPaletteSelect){updateOriginalInput(!0);hide()}else{updateOriginalInput()}}
return!1}
var paletteEvent=IE?"mousedown.spectrum":"click.spectrum touchstart.spectrum";paletteContainer.on(paletteEvent,".sp-thumb-el",paletteElementClick);initialColorContainer.on(paletteEvent,".sp-thumb-el:nth-child(1)",{ignore:!0},paletteElementClick)}
function updateSelectionPaletteFromStorage(){if(localStorageKey&&window.localStorage){try{var oldPalette=window.localStorage[localStorageKey].split(",#");if(oldPalette.length>1){delete window.localStorage[localStorageKey];$.each(oldPalette,function(i,c){addColorToSelectionPalette(c)})}}catch(e){}
try{selectionPalette=window.localStorage[localStorageKey].split(";")}catch(e){}}}
function addColorToSelectionPalette(color){if(showSelectionPalette){var rgb=tinycolor(color).toRgbString();if(!paletteLookup[rgb]&&$.inArray(rgb,selectionPalette)===-1){selectionPalette.push(rgb);while(selectionPalette.length>maxSelectionSize){selectionPalette.shift()}}
if(localStorageKey&&window.localStorage){try{window.localStorage[localStorageKey]=selectionPalette.join(";")}catch(e){}}}}
function getUniqueSelectionPalette(){var unique=[];if(opts.showPalette){for(var i=0;iviewWidth&&viewWidth>dpWidth)?Math.abs(offsetLeft+dpWidth-viewWidth):0);offsetTop-=Math.min(offsetTop,((offsetTop+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(dpHeight+inputHeight-extraY):extraY));return{top:offsetTop,bottom:offset.bottom,left:offsetLeft,right:offset.right,width:offset.width,height:offset.height}}
function noop(){}
function stopPropagation(e){e.stopPropagation()}
function bind(func,obj){var slice=Array.prototype.slice;var args=slice.call(arguments,2);return function(){return func.apply(obj,args.concat(slice.call(arguments)))}}
function draggable(element,onmove,onstart,onstop){onmove=onmove||function(){};onstart=onstart||function(){};onstop=onstop||function(){};var doc=document;var dragging=!1;var offset={};var maxHeight=0;var maxWidth=0;var hasTouch=('ontouchstart' in window);var duringDragEvents={};duringDragEvents.selectstart=prevent;duringDragEvents.dragstart=prevent;duringDragEvents["touchmove mousemove"]=move;duringDragEvents["touchend mouseup"]=stop;function prevent(e){if(e.stopPropagation){e.stopPropagation()}
if(e.preventDefault){e.preventDefault()}
e.returnValue=!1}
function move(e){if(dragging){if(IE&&doc.documentMode<9&&!e.button){return stop()}
var t0=e.originalEvent&&e.originalEvent.touches&&e.originalEvent.touches[0];var pageX=t0&&t0.pageX||e.pageX;var pageY=t0&&t0.pageY||e.pageY;var dragX=Math.max(0,Math.min(pageX-offset.left,maxWidth));var dragY=Math.max(0,Math.min(pageY-offset.top,maxHeight));if(hasTouch){prevent(e)}
onmove.apply(element,[dragX,dragY,e])}}
function start(e){var rightclick=(e.which)?(e.which==3):(e.button==2);if(!rightclick&&!dragging){if(onstart.apply(element,arguments)!==!1){dragging=!0;maxHeight=$(element).height();maxWidth=$(element).width();offset=$(element).offset();$(doc).on(duringDragEvents);$(doc.body).addClass("sp-dragging");move(e);prevent(e)}}}
function stop(){if(dragging){$(doc).off(duringDragEvents);$(doc.body).removeClass("sp-dragging");setTimeout(function(){onstop.apply(element,arguments)},0)}
dragging=!1}
$(element).on("touchstart mousedown",start)}
function throttle(func,wait,debounce){var timeout;return function(){var context=this,args=arguments;var throttler=function(){timeout=null;func.apply(context,args)};if(debounce)clearTimeout(timeout);if(debounce||!timeout)timeout=setTimeout(throttler,wait)}}
function inputTypeColorSupport(){return $.fn.spectrum.inputTypeColorSupport()}
var dataID="spectrum.id";$.fn.spectrum=function(opts,extra){if(typeof opts=="string"){var returnValue=this;var args=Array.prototype.slice.call(arguments,1);this.each(function(){var spect=spectrums[$(this).data(dataID)];if(spect){var method=spect[opts];if(!method){throw new Error("Spectrum: no such method: '"+opts+"'")}
if(opts=="get"){returnValue=spect.get()}else if(opts=="container"){returnValue=spect.container}else if(opts=="option"){returnValue=spect.option.apply(spect,args)}else if(opts=="destroy"){spect.destroy();$(this).removeData(dataID)}else{method.apply(spect,args)}}});return returnValue}
return this.spectrum("destroy").each(function(){var options=$.extend({},$(this).data(),opts);var spect=spectrum(this,options);$(this).data(dataID,spect.id)})};$.fn.spectrum.load=!0;$.fn.spectrum.loadOpts={};$.fn.spectrum.draggable=draggable;$.fn.spectrum.defaults=defaultOpts;$.fn.spectrum.inputTypeColorSupport=function inputTypeColorSupport(){if(typeof inputTypeColorSupport._cachedResult==="undefined"){var colorInput=$(" ")[0];inputTypeColorSupport._cachedResult=colorInput.type==="color"&&colorInput.value!==""}
return inputTypeColorSupport._cachedResult};$.spectrum={};$.spectrum.localization={};$.spectrum.palettes={};$.fn.spectrum.processNativeColorInputs=function(){var colorInputs=$("input[type=color]");if(colorInputs.length&&!inputTypeColorSupport()){colorInputs.spectrum({preferredFormat:"hex6"})}};(function(){var trimLeft=/^[\s,#]+/,trimRight=/\s+$/,tinyCounter=0,math=Math,mathRound=math.round,mathMin=math.min,mathMax=math.max,mathRandom=math.random;var tinycolor=function(color,opts){color=(color)?color:'';opts=opts||{};if(color instanceof tinycolor){return color}
if(!(this instanceof tinycolor)){return new tinycolor(color,opts)}
var rgb=inputToRGB(color);this._originalInput=color;this._r=rgb.r;this._g=rgb.g;this._b=rgb.b;this._a=rgb.a;this._roundA=mathRound(1000*this._a)/1000;this._format=opts.format||rgb.format;this._gradientType=opts.gradientType;if(this._r<1){this._r=mathRound(this._r)}
if(this._g<1){this._g=mathRound(this._g)}
if(this._b<1){this._b=mathRound(this._b)}
this._ok=rgb.ok;this._tc_id=tinyCounter++};tinycolor.prototype={isDark:function(){return this.getBrightness()<128},isLight:function(){return!this.isDark()},isValid:function(){return this._ok},getOriginalInput:function(){return this._originalInput},getFormat:function(){return this._format},getAlpha:function(){return this._a},getBrightness:function(){var rgb=this.toRgb();return(rgb.r*299+rgb.g*587+rgb.b*114)/1000},setAlpha:function(value){this._a=boundAlpha(value);this._roundA=mathRound(1000*this._a)/1000;return this},toHsv:function(){var hsv=rgbToHsv(this._r,this._g,this._b);return{h:hsv.h*360,s:hsv.s,v:hsv.v,a:this._a}},toHsvString:function(){var hsv=rgbToHsv(this._r,this._g,this._b);var h=mathRound(hsv.h*360),s=mathRound(hsv.s*100),v=mathRound(hsv.v*100);return(this._a==1)?"hsv("+h+", "+s+"%, "+v+"%)":"hsva("+h+", "+s+"%, "+v+"%, "+this._roundA+")"},toHsl:function(){var hsl=rgbToHsl(this._r,this._g,this._b);return{h:hsl.h*360,s:hsl.s,l:hsl.l,a:this._a}},toHslString:function(){var hsl=rgbToHsl(this._r,this._g,this._b);var h=mathRound(hsl.h*360),s=mathRound(hsl.s*100),l=mathRound(hsl.l*100);return(this._a==1)?"hsl("+h+", "+s+"%, "+l+"%)":"hsla("+h+", "+s+"%, "+l+"%, "+this._roundA+")"},toHex:function(allow3Char){return rgbToHex(this._r,this._g,this._b,allow3Char)},toHexString:function(allow3Char){return'#'+this.toHex(allow3Char)},toHex8:function(){return rgbaToHex(this._r,this._g,this._b,this._a)},toHex8String:function(){return'#'+this.toHex8()},toRgb:function(){return{r:mathRound(this._r),g:mathRound(this._g),b:mathRound(this._b),a:this._a}},toRgbString:function(){return(this._a==1)?"rgb("+mathRound(this._r)+", "+mathRound(this._g)+", "+mathRound(this._b)+")":"rgba("+mathRound(this._r)+", "+mathRound(this._g)+", "+mathRound(this._b)+", "+this._roundA+")"},toPercentageRgb:function(){return{r:mathRound(bound01(this._r,255)*100)+"%",g:mathRound(bound01(this._g,255)*100)+"%",b:mathRound(bound01(this._b,255)*100)+"%",a:this._a}},toPercentageRgbString:function(){return(this._a==1)?"rgb("+mathRound(bound01(this._r,255)*100)+"%, "+mathRound(bound01(this._g,255)*100)+"%, "+mathRound(bound01(this._b,255)*100)+"%)":"rgba("+mathRound(bound01(this._r,255)*100)+"%, "+mathRound(bound01(this._g,255)*100)+"%, "+mathRound(bound01(this._b,255)*100)+"%, "+this._roundA+")"},toName:function(){if(this._a===0){return"transparent"}
if(this._a<1){return!1}
return hexNames[rgbToHex(this._r,this._g,this._b,!0)]||!1},toFilter:function(secondColor){var hex8String='#'+rgbaToHex(this._r,this._g,this._b,this._a);var secondHex8String=hex8String;var gradientType=this._gradientType?"GradientType = 1, ":"";if(secondColor){var s=tinycolor(secondColor);secondHex8String=s.toHex8String()}
return"progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"},toString:function(format){var formatSet=!!format;format=format||this._format;var formattedString=!1;var hasAlpha=this._a<1&&this._a>=0;var needsAlphaFormat=!formatSet&&hasAlpha&&(format==="hex"||format==="hex6"||format==="hex3"||format==="name");if(needsAlphaFormat){if(format==="name"&&this._a===0){return this.toName()}
return this.toRgbString()}
if(format==="rgb"){formattedString=this.toRgbString()}
if(format==="prgb"){formattedString=this.toPercentageRgbString()}
if(format==="hex"||format==="hex6"){formattedString=this.toHexString()}
if(format==="hex3"){formattedString=this.toHexString(!0)}
if(format==="hex8"){formattedString=this.toHex8String()}
if(format==="name"){formattedString=this.toName()}
if(format==="hsl"){formattedString=this.toHslString()}
if(format==="hsv"){formattedString=this.toHsvString()}
return formattedString||this.toHexString()},_applyModification:function(fn,args){var color=fn.apply(null,[this].concat([].slice.call(args)));this._r=color._r;this._g=color._g;this._b=color._b;this.setAlpha(color._a);return this},lighten:function(){return this._applyModification(lighten,arguments)},brighten:function(){return this._applyModification(brighten,arguments)},darken:function(){return this._applyModification(darken,arguments)},desaturate:function(){return this._applyModification(desaturate,arguments)},saturate:function(){return this._applyModification(saturate,arguments)},greyscale:function(){return this._applyModification(greyscale,arguments)},spin:function(){return this._applyModification(spin,arguments)},_applyCombination:function(fn,args){return fn.apply(null,[this].concat([].slice.call(args)))},analogous:function(){return this._applyCombination(analogous,arguments)},complement:function(){return this._applyCombination(complement,arguments)},monochromatic:function(){return this._applyCombination(monochromatic,arguments)},splitcomplement:function(){return this._applyCombination(splitcomplement,arguments)},triad:function(){return this._applyCombination(triad,arguments)},tetrad:function(){return this._applyCombination(tetrad,arguments)}};tinycolor.fromRatio=function(color,opts){if(typeof color=="object"){var newColor={};for(var i in color){if(color.hasOwnProperty(i)){if(i==="a"){newColor[i]=color[i]}else{newColor[i]=convertToPercentage(color[i])}}}
color=newColor}
return tinycolor(color,opts)};function inputToRGB(color){var rgb={r:0,g:0,b:0};var a=1;var ok=!1;var format=!1;if(typeof color=="string"){color=stringInputToObject(color)}
if(typeof color=="object"){if(color.hasOwnProperty("r")&&color.hasOwnProperty("g")&&color.hasOwnProperty("b")){rgb=rgbToRgb(color.r,color.g,color.b);ok=!0;format=String(color.r).substr(-1)==="%"?"prgb":"rgb"}else if(color.hasOwnProperty("h")&&color.hasOwnProperty("s")&&color.hasOwnProperty("v")){color.s=convertToPercentage(color.s);color.v=convertToPercentage(color.v);rgb=hsvToRgb(color.h,color.s,color.v);ok=!0;format="hsv"}else if(color.hasOwnProperty("h")&&color.hasOwnProperty("s")&&color.hasOwnProperty("l")){color.s=convertToPercentage(color.s);color.l=convertToPercentage(color.l);rgb=hslToRgb(color.h,color.s,color.l);ok=!0;format="hsl"}
if(color.hasOwnProperty("a")){a=color.a}}
a=boundAlpha(a);return{ok:ok,format:color.format||format,r:mathMin(255,mathMax(rgb.r,0)),g:mathMin(255,mathMax(rgb.g,0)),b:mathMin(255,mathMax(rgb.b,0)),a:a}}
function rgbToRgb(r,g,b){return{r:bound01(r,255)*255,g:bound01(g,255)*255,b:bound01(b,255)*255}}
function rgbToHsl(r,g,b){r=bound01(r,255);g=bound01(g,255);b=bound01(b,255);var max=mathMax(r,g,b),min=mathMin(r,g,b);var h,s,l=(max+min)/2;if(max==min){h=s=0}else{var d=max-min;s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p}
if(s===0){r=g=b=l}else{var q=l<0.5?l*(1+s):l+s-l*s;var p=2*l-q;r=hue2rgb(p,q,h+1/3);g=hue2rgb(p,q,h);b=hue2rgb(p,q,h-1/3)}
return{r:r*255,g:g*255,b:b*255}}
function rgbToHsv(r,g,b){r=bound01(r,255);g=bound01(g,255);b=bound01(b,255);var max=mathMax(r,g,b),min=mathMin(r,g,b);var h,s,v=max;var d=max-min;s=max===0?0:d/max;if(max==min){h=0}else{switch(max){case r:h=(g-b)/d+(g>1))+720)%360;--results;){hsl.h=(hsl.h+part)%360;ret.push(tinycolor(hsl))}
return ret}
function monochromatic(color,results){results=results||6;var hsv=tinycolor(color).toHsv();var h=hsv.h,s=hsv.s,v=hsv.v;var ret=[];var modification=1/results;while(results--){ret.push(tinycolor({h:h,s:s,v:v}));v=(v+modification)%1}
return ret}
tinycolor.mix=function(color1,color2,amount){amount=(amount===0)?0:(amount||50);var rgb1=tinycolor(color1).toRgb();var rgb2=tinycolor(color2).toRgb();var p=amount/100;var w=p*2-1;var a=rgb2.a-rgb1.a;var w1;if(w*a==-1){w1=w}else{w1=(w+a)/(1+w*a)}
w1=(w1+1)/2;var w2=1-w1;var rgba={r:rgb2.r*w1+rgb1.r*w2,g:rgb2.g*w1+rgb1.g*w2,b:rgb2.b*w1+rgb1.b*w2,a:rgb2.a*p+rgb1.a*(1-p)};return tinycolor(rgba)};tinycolor.readability=function(color1,color2){var c1=tinycolor(color1);var c2=tinycolor(color2);var rgb1=c1.toRgb();var rgb2=c2.toRgb();var brightnessA=c1.getBrightness();var brightnessB=c2.getBrightness();var colorDiff=(Math.max(rgb1.r,rgb2.r)-Math.min(rgb1.r,rgb2.r)+Math.max(rgb1.g,rgb2.g)-Math.min(rgb1.g,rgb2.g)+Math.max(rgb1.b,rgb2.b)-Math.min(rgb1.b,rgb2.b));return{brightness:Math.abs(brightnessA-brightnessB),color:colorDiff}};tinycolor.isReadable=function(color1,color2){var readability=tinycolor.readability(color1,color2);return readability.brightness>125&&readability.color>500};tinycolor.mostReadable=function(baseColor,colorList){var bestColor=null;var bestScore=0;var bestIsReadable=!1;for(var i=0;i125&&readability.color>500;var score=3*(readability.brightness/125)+(readability.color/500);if((readable&&!bestIsReadable)||(readable&&bestIsReadable&&score>bestScore)||((!readable)&&(!bestIsReadable)&&score>bestScore)){bestIsReadable=readable;bestScore=score;bestColor=tinycolor(colorList[i])}}
return bestColor};var names=tinycolor.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"663399",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"};var hexNames=tinycolor.hexNames=flip(names);function flip(o){var flipped={};for(var i in o){if(o.hasOwnProperty(i)){flipped[o[i]]=i}}
return flipped}
function boundAlpha(a){a=parseFloat(a);if(isNaN(a)||a<0||a>1){a=1}
return a}
function bound01(n,max){if(isOnePointZero(n)){n="100%"}
var processPercent=isPercentage(n);n=mathMin(max,mathMax(0,parseFloat(n)));if(processPercent){n=parseInt(n*max,10)/100}
if((math.abs(n-max)<0.000001)){return 1}
return(n%max)/parseFloat(max)}
function clamp01(val){return mathMin(1,mathMax(0,val))}
function parseIntFromHex(val){return parseInt(val,16)}
function isOnePointZero(n){return typeof n=="string"&&n.indexOf('.')!=-1&&parseFloat(n)===1}
function isPercentage(n){return typeof n==="string"&&n.indexOf('%')!=-1}
function pad2(c){return c.length==1?'0'+c:''+c}
function convertToPercentage(n){if(n<=1){n=(n*100)+"%"}
return n}
function convertDecimalToHex(d){return Math.round(parseFloat(d)*255).toString(16)}
function convertHexToDecimal(h){return(parseIntFromHex(h)/255)}
var matchers=(function(){var CSS_INTEGER="[-\\+]?\\d+%?";var CSS_NUMBER="[-\\+]?\\d*\\.\\d+%?";var CSS_UNIT="(?:"+CSS_NUMBER+")|(?:"+CSS_INTEGER+")";var PERMISSIVE_MATCH3="[\\s|\\(]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")\\s*\\)?";var PERMISSIVE_MATCH4="[\\s|\\(]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")\\s*\\)?";return{rgb:new RegExp("rgb"+PERMISSIVE_MATCH3),rgba:new RegExp("rgba"+PERMISSIVE_MATCH4),hsl:new RegExp("hsl"+PERMISSIVE_MATCH3),hsla:new RegExp("hsla"+PERMISSIVE_MATCH4),hsv:new RegExp("hsv"+PERMISSIVE_MATCH3),hsva:new RegExp("hsva"+PERMISSIVE_MATCH4),hex3:/^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex8:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/}})();function stringInputToObject(color){color=color.replace(trimLeft,'').replace(trimRight,'').toLowerCase();var named=!1;if(names[color]){color=names[color];named=!0}else if(color=='transparent'){return{r:0,g:0,b:0,a:0,format:"name"}}
var match;if((match=matchers.rgb.exec(color))){return{r:match[1],g:match[2],b:match[3]}}
if((match=matchers.rgba.exec(color))){return{r:match[1],g:match[2],b:match[3],a:match[4]}}
if((match=matchers.hsl.exec(color))){return{h:match[1],s:match[2],l:match[3]}}
if((match=matchers.hsla.exec(color))){return{h:match[1],s:match[2],l:match[3],a:match[4]}}
if((match=matchers.hsv.exec(color))){return{h:match[1],s:match[2],v:match[3]}}
if((match=matchers.hsva.exec(color))){return{h:match[1],s:match[2],v:match[3],a:match[4]}}
if((match=matchers.hex8.exec(color))){return{a:convertHexToDecimal(match[1]),r:parseIntFromHex(match[2]),g:parseIntFromHex(match[3]),b:parseIntFromHex(match[4]),format:named?"name":"hex8"}}
if((match=matchers.hex6.exec(color))){return{r:parseIntFromHex(match[1]),g:parseIntFromHex(match[2]),b:parseIntFromHex(match[3]),format:named?"name":"hex"}}
if((match=matchers.hex3.exec(color))){return{r:parseIntFromHex(match[1]+''+match[1]),g:parseIntFromHex(match[2]+''+match[2]),b:parseIntFromHex(match[3]+''+match[3]),format:named?"name":"hex"}}
return!1}
window.tinycolor=tinycolor})();$(function(){if($.fn.spectrum.load){$.fn.spectrum.processNativeColorInputs()}})});
$('head').append('');
}; // end setupColorpickerSpectrum
// improve the original time display function, to enable display of time in minutes, hours or days:
self.ago = function(time, now) {
if (window.plugin.playerTrackerAddon.settings.showdatetime) {
if (!(time instanceof Date)) {
if (time) {
time = new Date(time);
} else {
time = new Date();
}
}
// yyyy-mm-dd hh:mm
return (self.settings.hidedatetoday && new Date().toDateString() == time.toDateString() ? "" : [time.getFullYear(),time.getMonth()+1,time.getDate()].join('-') + ' ') + [time.getHours(),('0' + time.getMinutes()).slice(-2)].join(':');
}
// d h m
let s = (now-time) / 1000;
let m = Math.floor((s % 3600) / 60);
let h = Math.floor(s / 3600);
let d = Math.floor(h / 24);
let returnVal = m + 'm';
if (h > 24) {
h = Math.floor(h % 24);
}
if (h > 0) {
returnVal = h + 'h' + returnVal;
}
if (d > 0) {
returnVal = d + 'd' + returnVal;
}
return returnVal;
};
self.setup = function() {
if (!window.plugin.playerTracker) {
console.warn('IITC plugin ERROR: ' + self.title + ' version ' + self.version + ' - window.plugin.playerTracker required');
return;
}
if (!window.plugin.playerTracker.drawnTracesEnl) {
if (window.iitcLoaded) {
console.warn('IITC plugin ERROR: ' + self.title + ' version ' + self.version + ' - window.plugin.playerTracker.drawnTracesEnl required');
return;
}
console.log('IITC plugin: ' + self.title + ' version ' + self.version + ' - wait for window.plugin.playerTracker');
// window.addHook('iitcLoaded',self.setup);
// inject add-on setup into the last function of the playerTracker setup function:
let playerTracker_setupUserSearch = window.plugin.playerTracker.setupUserSearch;
window.plugin.playerTracker.setupUserSearch = function() {
playerTracker_setupUserSearch();
self.setup();
}
return;
}
if ('pluginloaded' in self) {
console.log('IITC plugin already loaded: ' + self.title + ' version ' + self.version);
return;
} else {
self.pluginloaded = true;
}
self.setupMarkerlabel();
self.setupColorpickerSpectrum();
self.restoresettings();
// inject code for Machina:
if (!window.plugin.playerTracker.iconMac) {
let iconMacImage = 'data:image/png;base64,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';
let iconMacRetImage = 'data:image/png;base64,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';
window.plugin.playerTracker.iconMac = window.L.Icon.Default.extend({options: {
iconUrl: iconMacImage,
iconRetinaUrl: iconMacRetImage
}});
}
// add layer chooser for Machina:
if (!window.plugin.playerTracker.drawnTracesMac) {
window.plugin.playerTracker.drawnTracesMac = new window.L.LayerGroup();
if ('addOverlay' in window.layerChooser) {
window.layerChooser.addOverlay(window.plugin.playerTracker.drawnTracesMac, `Player Tracker ${machina}`,{default: true});
} else { // before IITC 0.34:
window.addLayerGroup(`Player Tracker ${machina}`, window.plugin.playerTracker.drawnTracesMac, true);
}
window.map.on('layeradd',function(obj) {
if (obj.layer === window.plugin.playerTracker.drawnTracesMac) {
obj.layer.eachLayer(function(marker) {
if (marker._icon) window.setupTooltips($(marker._icon));
});
}
});
}
try {
self.labelsetup();
self.modify_processNewData();
self.modify_drawData();
self.modify_ago();
self.resettracks();
} catch(e) {
console.warn('IITC plugin ERROR: ' + self.title + ' version ' + self.version + ' - setup failed');
return;
}
// inject code for Machina:
if (functionExists('window.plugin.playerTracker.closeIconTooltips') && !window.plugin.playerTracker.closeIconTooltips.toString().match(/Mac/)) {
let original_closeIconTooltips = window.plugin.playerTracker.closeIconTooltips;
window.plugin.playerTracker.closeIconTooltips = function() {
original_closeIconTooltips();
window.plugin.playerTracker.drawnTracesMac.eachLayer(function (layer) {
if ($(layer._icon)) {
$(layer._icon).tooltip('close');
}
});
};
if (functionExists('window.plugin.playerTracker.zoomListener')) {
let original_zoomListener = window.plugin.playerTracker.zoomListener;
window.plugin.playerTracker.zoomListener = function() {
original_zoomListener();
if (window.map.getZoom() < window.PLAYER_TRACKER_MIN_ZOOM) {
window.plugin.playerTracker.drawnTracesMac.clearLayers();
}
};
}
}
if (functionExists('window.plugin.playerTracker.handleData')) {
// add Machina clearLayers
let handleData_override = window.plugin.playerTracker.handleData.toString();
handleData_override = replaceText(handleData_override,'}',` ${self.namespace}updateplayerlist();\n}`);
if (!handleData_override.match(/drawnTracesMac/)) {
handleData_override = replaceText(handleData_override,/(clearLayers.*?\n)/s,'$1 window.plugin.playerTracker.drawnTracesMac.clearLayers();\n');
}
replaceFunction('window.plugin.playerTracker.handleData',handleData_override);
// replace the playerTracker publicChatDataAvailable handleData hook:
for (let callback of window._hooks.publicChatDataAvailable) {
if (callback.toString().match('playerTracker')) {
window.removeHook('publicChatDataAvailable',callback);
break;
}
}
window.addHook('publicChatDataAvailable',window.plugin.playerTracker.handleData);
}
self.setlimit(self.settings.limit);
//add options menu
let toolboxlink = document.getElementById('toolbox').appendChild(document.createElement('a'));
toolboxlink.textContent = self.title;
toolboxlink.addEventListener('click', function(e) {
e.preventDefault();
self.menu();
}, false);
let stylesheet = document.body.appendChild(document.createElement('style'));
stylesheet.innerHTML = `
.${self.id}menu > a { display:block; color:#ffce00; border:1px solid #ffce00; padding:3px 0; margin:10px auto; width:80%; text-align:center; background:rgba(8,48,78,.9); }
.${self.id}menu > label { user-select: none; }
.${self.id}author { margin-top: 14px; font-style: italic; font-size: smaller; }
`;
console.log('IITC plugin loaded: ' + self.title + ' version ' + self.version);
};
self.runSetupRightAfterPlayerTracker = function() {
if (!window.plugin.playerTracker?.setupUserSearch) {
self.setup();
return;
}
// setupUserSearch is the last called function of the playerTracker setup
// inject setup for this add-on into that function, to make sure the layer chooser for machina will be placed right under the others:
let playerTracker_setupUserSearch = window.plugin.playerTracker.setupUserSearch;
window.plugin.playerTracker.setupUserSearch = function() {
playerTracker_setupUserSearch();
self.setup();
}
}
var setup = self.runSetupRightAfterPlayerTracker;
// set priority to boot, to make sure the add-on will run before player-activity-tracker setup:
setup.priority = 'boot';
// Added to support About IITC details and changelog:
plugin_info.script.version = plugin_info.script.version.replace(/\.\d{8}\.\d{6}$/,'');
plugin_info.buildName = 'softspot.nl';
plugin_info.dateTimeVersion = self.version.replace(/^.*(\d{4})(\d{2})(\d{2})\.(\d{6})/,'$1-$2-$3-$4');
plugin_info.pluginId = self.id;
let changelog = [{version:'This is a softspot.nl plugin by ' + self.author,changes:[]},...self.changelog.replace(/^.*?version /s,'').split(/\nversion /).map((v)=>{v=v.split(/\n/).map((l)=>{return l.replace(/^- /,'')}).filter((l)=>{return l != "";}); return {version:v.shift(),changes:v}})];
setup.info = plugin_info; //add the script info data to the function as a property
if (typeof changelog !== 'undefined') setup.info.changelog = changelog;
if(!window.bootPlugins) window.bootPlugins = [];
window.bootPlugins.push(setup);
// if IITC has already booted, immediately run the 'setup' function
if(window.iitcLoaded && typeof setup === 'function') setup();
} // wrapper end
// inject code into site context
var script = document.createElement('script');
var info = {};
if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description };
script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');'));
(document.body || document.head || document.documentElement).appendChild(script);