// ==UserScript==
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @version 0.0.6.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Display a sortable list of all localized portails with team, level, resonators informations
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// ==/UserScript==
/* whatsnew
* 0.0.6 : Add power charge information into a new column + bugfix
* 0.0.5 : Filter portals by clicking on 'All portals', 'Res Portals' or 'Enl Portals'
* 0.0.4 : Add link to portals name, one click to display full information in portal panel, double click to zoom on portal, hover to show address
* 0.0.3 : sorting ascending/descending and add numbers of portals by faction on top on table
* 0.0.2 : add sorting feature when click on header column
* 0.0.1 : initial release, show list of portals with level, team, resonators and shield information
* Display code inspired from @vita10gy's scoreboard plugin : iitc-plugin-scoreboard@vita10gy - https://github.com/breunigs/ingress-intel-total-conversion
* Portal link code from xelio - iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
*
* todo :
*/
function wrapper() {
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalslist = function() {};
window.plugin.portalslist.listPortals = []; // structure : name, team, level, resonators = Array, Shields = Array, APgain
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
window.plugin.portalslist.filter=0;
//fill the listPortals array with portals avalaible on the map (level filtered portals will not appear in the table)
window.plugin.portalslist.getPortals = function(){
//filter : 0 = All, 1 = Res, 2 = Enl
//console.log('** getPortals');
var retval=false;
window.plugin.portalslist.listPortals = [];
//get portals informations from IITC
$.each(window.portals, function(i, portal) {
retval=true;
var d = portal.options.details;
var name = d.portalV2.descriptiveText.TITLE;
var team = portal.options.team;
switch (team){
case 1 :
window.plugin.portalslist.resP++;
break;
case 2 :
window.plugin.portalslist.enlP++;
break;
}
var level = getPortalLevel(d).toFixed(2);
var guid = portal.options.guid;
//get resonators informations
var resonators = []; // my local resonator array : reso level, reso deployed by, distance to portal, energy total, max
var energy = 0;
var maxenergy=0;
$.each(portal.options.details.resonatorArray.resonators, function(ind, reso) {
if(reso) {
resonators[ind] = [reso.level, window.getPlayerName(reso.ownerGuid), reso.distanceToPortal, reso.energyTotal, RESO_NRG[reso.level]];
energy += reso.energyTotal;
maxenergy += RESO_NRG[reso.level];
} else { resonators[ind] = [0,'',0,0,0]; }
});
// Sort resonators array by resonator level
resonators.sort(function (a, b) {return b[0] - a[0]});
//get shield informations
var shields = [];
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if (mod)
shields[ind] = mod.rarity.capitalize().replace('_', ' ');
else
shields[ind] = '';
});
var APgain= getAttackApGain(d).enemyAp;
var thisPortal = {'portal':d,'name':name,'team':team,'level':level,'guid':guid, 'resonators':resonators,'energy' : Math.floor(energy/maxenergy*100), 'shields':shields,'APgain':APgain};
window.plugin.portalslist.listPortals.push(thisPortal);
});
return retval;
}
window.plugin.portalslist.displayPL = function() {
//console.log('** displayPL');
var html = '';
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
if (window.plugin.portalslist.getPortals()) {
html += window.plugin.portalslist.portalTable('level', window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter);
} else {
html = '
';
};
alert('' + html + '
');
$(".ui-dialog").addClass('ui-dialog-portalslist');
// Setup sorting
$(document).on('click', '#portalslist table th', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter));
});
$(document).on('click', '#portalslist .filterAll', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,0));
});
$(document).on('click', '#portalslist .filterRes', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,1));
});
$(document).on('click', '#portalslist .filterEnl', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,2));
});
}
window.plugin.portalslist.portalTable = function(sortBy, sortOrder, filter) {
// sortOrder <0 ==> desc, >0 ==> asc, i use sortOrder * -1 to change the state
window.plugin.portalslist.filter=filter;
var portals=window.plugin.portalslist.listPortals;
// console.log('********************* Sort by ' + sortBy + ' order : ' + sortOrder + ' filter : ' + filter);
//Array sort
window.plugin.portalslist.listPortals.sort(function(a, b) {
var retVal = 0;
switch (sortBy) {
case 'names':
retVal = a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
break;
case 'r1':
retVal = b.resonators[0][0] - a.resonators[0][0];
break;
case 'r2':
retVal = b.resonators[1][0] - a.resonators[1][0];
break;
case 'r3':
retVal = b.resonators[2][0] - a.resonators[2][0];
break;
case 'r4':
retVal = b.resonators[3][0] - a.resonators[3][0];
break;
case 'r5':
retVal = b.resonators[4][0] - a.resonators[4][0];
break;
case 'r6':
retVal = b.resonators[5][0] - a.resonators[5][0];
break;
case 'r7':
retVal = b.resonators[6][0] - a.resonators[6][0];
break;
case 'r8':
retVal = b.resonators[7][0] - a.resonators[7][0];
break;
case 's1':
retVal = a.shields[0].toLowerCase() > b.shields[0].toLowerCase() ? -1 : 1;
break;
case 's2':
retVal = a.shields[1].toLowerCase() > b.shields[1].toLowerCase() ? -1 : 1;
break;
case 's3':
retVal = a.shields[2].toLowerCase() > b.shields[2].toLowerCase() ? -1 : 1;
break;
case 's4':
retVal = a.shields[3].toLowerCase() > b.shields[3].toLowerCase() ? -1 : 1;
break;
default:
retVal = b[sortBy] - a[sortBy];
break;
}
if (sortOrder > 0) { retVal = -retVal} //thx @jonatkins
return retVal;
});
var sort = window.plugin.portalslist.portalTableSort;
var html = window.plugin.portalslist.stats();
html += ''
+ 'Portal | '
+ 'Level | '
+ 'Team | '
+ 'R1 | '
+ 'R2 | '
+ 'R3 | '
+ 'R4 | '
+ 'R5 | '
+ 'R6 | '
+ 'R7 | '
+ 'R8 | '
+ 'Energy | '
+ 'Shield 1 | '
+ 'Shield 2 | '
+ 'Shield 3 | '
+ 'Shield 4 | '
+ 'AP Gain |
';
$.each(portals, function(ind, portal) {
if (filter === 0 || filter === portal.team){
html += ''
+ '' + window.plugin.portalslist.getPortalLink(portal.portal, portal.guid) + ' | '
//+ '' + portal.name + ' | '
+ '' + portal.level + ' | '
+ '' + portal.team + ' | '
+ '' + portal.resonators[0][0] + ' | '
//+ '6'
+ ' | ' + portal.resonators[1][0] + ' | '
+ '' + portal.resonators[2][0] + ' | '
+ '' + portal.resonators[3][0] + ' | '
+ '' + portal.resonators[4][0] + ' | '
+ '' + portal.resonators[5][0] + ' | '
+ '' + portal.resonators[6][0] + ' | '
+ '' + portal.resonators[7][0] + ' | '
+ '' + portal.energy + '% | '
+ '' + portal.shields[0] + ' | '
+ '' + portal.shields[1] + ' | '
+ '' + portal.shields[2] + ' | '
+ '' + portal.shields[3] + ' | '
+ '' + portal.APgain + ' | ';
html+= '
';
}
});
html+='
';
html+= 'Click on portals table headers to sort by that column.
'
+ 'Click on All Portals, Resistant Portals, Enlightened Portals to filter
'
+ 'Thanks to @vita10gy & @xelio for their IITC plugins who inspired me. A
@teo96 production. Vive la Résistance !
';
window.plugin.portalslist.sortOrder = window.plugin.portalslist.sortOrder*-1;
return html;
}
window.plugin.portalslist.stats = function(sortBy) {
//console.log('** stats');
var html = ''
+ 'All Portals : (click to filter) | ' + window.plugin.portalslist.listPortals.length +' | '
+ 'Resistant Portals : | ' + window.plugin.portalslist.resP + ' | '
+ 'Enlightened Portals : | '+ window.plugin.portalslist.enlP + ' | '
+ '
'
+ '
';
return html;
}
// A little helper functon so the above isn't so messy
window.plugin.portalslist.portalTableSort = function(name, by) {
var retVal = 'data-sort="' + name + '"';
if(name === by) {
retVal += ' class="sorted"';
}
return retVal;
};
// portal link - single click: select portal
// double click: zoom to and select portal
// hover: show address
// code from getPortalLink function by xelio from iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
window.plugin.portalslist.getPortalLink = function(portal,guid) {
var latlng = [portal.locationE6.latE6/1E6, portal.locationE6.lngE6/1E6].join();
var jsSingleClick = 'window.renderPortalDetails(\''+guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
var perma = 'https://ingress.com/intel?latE6='+portal.locationE6.latE6+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+guid;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('',{
"class": 'help',
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
var div = ''+a+'
';
return div;
}
var setup = function() {
$('body').append('');
$('#toolbox').append('Portals List');
$('head').append('');
}
// PLUGIN END //////////////////////////////////////////////////////////
if(window.iitcLoaded && typeof setup === 'function') {
setup();
} else {
if(window.bootPlugins)
window.bootPlugins.push(setup);
else
window.bootPlugins = [setup];
}
} // wrapper end
// inject code into site context
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ wrapper +')();'));
(document.body || document.head || document.documentElement).appendChild(script);