diff --git a/plugins/portals-list.user.js b/plugins/portals-list.user.js new file mode 100644 index 00000000..c010cde6 --- /dev/null +++ b/plugins/portals-list.user.js @@ -0,0 +1,385 @@ +// ==UserScript== +// @id iitc-plugin-portals-list@teo96 +// @name teo96: show list of portals +// @version 0.0.6 +// @namespace https://github.com/teo96/iitc-plugins/ +// @updateURL https://raw.github.com/teo96/iitc-plugins/master/portals-list.user.js +// @downloadURL https://raw.github.com/teo96/iitc-plugins/master/portals-list.user.js +// @description Display a sortable list of all localized portails with team, level, resonators informations +// @include https://www.ingress.com/intel* +// @match https://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 (by 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; + + //var player = portal.options.details.captured.capturingPlayerId; + //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 = '
Nothing to Show !
'; + }; + 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); + //tri du tableau window.plugin.portalslist.listPortals + window.plugin.portalslist.listPortals.sort(function(a, b) { + var retVal = 0; + + if (sortOrder < 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; + } + } + else + { + switch (sortBy) { + case 'names': + retVal = a.name.toLowerCase() > b.name.toLowerCase() ? -1 : 1; + break; + case 'r1': + retVal = a.resonators[0][0] - b.resonators[0][0]; + break; + case 'r2': + retVal = a.resonators[1][0] - b.resonators[1][0]; + break; + case 'r3': + retVal = a.resonators[2][0] - b.resonators[2][0]; + break; + case 'r4': + retVal = a.resonators[3][0] - b.resonators[3][0]; + break; + case 'r5': + retVal = a.resonators[4][0] - b.resonators[4][0]; + break; + case 'r6': + retVal = a.resonators[5][0] - b.resonators[5][0]; + break; + case 'r7': + retVal = a.resonators[6][0] - b.resonators[6][0]; + break; + case 'r8': + retVal = a.resonators[7][0] - b.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 = a[sortBy] - b[sortBy]; + break; + } + } + return retVal; + }); + + var sort = window.plugin.portalslist.portalTableSort; + var html = window.plugin.portalslist.stats(); + html += '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + + + $.each(portals, function(ind, portal) { + + if (filter === 0 || filter === portal.team){ + html += '' + + '' + //+ '' + + '' + + '' + + '' + //+ '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + + html+= ''; + } + + }); + html+='
PortalLevelTeamR1R2R3R4R5R6R7R8EnergyShield 1Shield 2Shield 3Shield 4AP Gain
' + 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+= '
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);