diff --git a/plugins/portals-list.user.js b/plugins/portals-list.user.js
index 88bb636b..e98e60e1 100644
--- a/plugins/portals-list.user.js
+++ b/plugins/portals-list.user.js
@@ -1,15 +1,257 @@
// ==UserScript==
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
-// @category Deleted
-// @version 0.0.18.@@DATETIMEVERSION@@
+// @category Info
+// @version 0.0.19.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
-// @description PLUGIN CURRENTLY UNAVAILABLE
+// @description [@@BUILDNAME@@-@@BUILDDATE@@] Display a sortable list of all visible portals with full details about the team, resonators, shields, etc.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
+
+@@PLUGINSTART@@
+
+// PLUGIN START ////////////////////////////////////////////////////////
+
+ /* whatsnew
+ * 0.0.19: Using the new data format
+ * 0.0.15: Add 'age' column to display how long each portal has been controlled by its current owner.
+ * 0.0.14: Add support to new mods (S:Shield - T:Turret - LA:Link Amp - H:Heat-sink - M:Multi-hack - FA:Force Amp)
+ * 0.0.12: Use dialog() instead of alert so the user can drag the box around
+ * 0.0.11: Add nominal energy column and # links, fix sort bug when opened even amounts of times, nits
+ * 0.0.10: Fixed persistent css problem with alert
+ * 0.0.9 : bugs hunt
+ * 0.0.8 : Aborted to avoid problems with Niantic (export portals informations as csv or kml file)
+ * 0.0.7 : more informations available via tooltips (who deployed, energy, ...), new E/AP column
+ * 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 : export as GPX, Open in Google Maps, more statistics in the header, what else ?
+ */
+
+// use own namespace for plugin
+window.plugin.portalslist = function() {};
+
+window.plugin.portalslist.listPortals = [];
+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 avaliable on the map (level filtered portals will not appear in the table)
+window.plugin.portalslist.getPortals = function() {
+ //filter : 0 = All, 1 = Res, 2 = Enl
+ var retval=false;
+
+ var displayBounds = map.getBounds();
+
+ window.plugin.portalslist.listPortals = [];
+ $.each(window.portals, function(i, portal) {
+ // eliminate offscreen portals (selected, and in padding)
+ if(!displayBounds.contains(portal.getLatLng())) return true;
+
+ retval=true;
+ var d = portal.options.data;
+ var teamN = 0;
+
+ switch (d.team){
+ case 'RESISTANCE' :
+ window.plugin.portalslist.resP++;
+ teamN = 1
+ break;
+ case 'ENLIGHTENED' :
+ window.plugin.portalslist.enlP++;
+ teamN = 2;
+ break;
+ }
+
+ var thisPortal = {
+ 'guid': i,
+ 'teamN': teamN,
+ 'name': d.title,
+ 'team': d.team,
+ 'level': d.level,
+ 'health': d.health,
+ 'resCount': d.resCount,
+ 'lat': d.latE6,
+ 'lng': d.lngE6,
+ 'img': d.img};
+ window.plugin.portalslist.listPortals.push(thisPortal);
+ });
+
+ return retval;
+}
+
+window.plugin.portalslist.displayPL = function() {
+ 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 = '
';
+ };
+
+ dialog({
+ html: '' + html + '
',
+ dialogClass: 'ui-dialog-portalslist',
+ title: 'Portal list: ' + window.plugin.portalslist.listPortals.length + ' ' + (window.plugin.portalslist.listPortals.length == 1 ? 'portal' : 'portals'),
+ id: 'portal-list',
+ width: 800
+ });
+
+ //run the name resolving process
+ //resolvePlayerNames();
+}
+
+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;
+
+ //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;
+ 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 | '
+ + 'Health | '
+ + 'Resonator Count | '
+
+
+ $.each(portals, function(ind, portal) {
+ if (filter === 0 || filter === portal.teamN) {
+ html += '
---|
'
+ + '' + window.plugin.portalslist.getPortalLink(portal, portal.guid) + ' | '
+ + '' + portal.level + ' | '
+ + '' + portal.team + ' | ';
+
+ html += '' + portal.health + ' | '
+ + '' + portal.resCount + ' | ';
+
+ html+= '
';
+ }
+ });
+ html += '
';
+
+ html += 'Click on portals table headers to sort by that column. '
+ + 'Click on
All Portals, Resistance 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) {
+ var html = ''
+ + 'All Portals : (click to filter) | ' + window.plugin.portalslist.listPortals.length + ' | '
+ + 'Resistance Portals : | ' + window.plugin.portalslist.resP +' (' + Math.floor(window.plugin.portalslist.resP/window.plugin.portalslist.listPortals.length*100) + '%) | '
+ + 'Enlightened Portals : | '+ window.plugin.portalslist.enlP +' (' + Math.floor(window.plugin.portalslist.enlP/window.plugin.portalslist.listPortals.length*100) + '%) | '
+ + '
'
+ + '
';
+ return html;
+}
+
+// A little helper function 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.latE6/1E6, portal.lngE6/1E6].join();
+ var jsSingleClick = 'window.renderPortalDetails(\''+guid+'\');return false';
+ var jsDoubleClick = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
+ var perma = '/intel?latE6='+portal.latE6+'&lngE6='+portal.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.name,
+ title: portal.name,
+ href: perma,
+ onClick: jsSingleClick,
+ onDblClick: jsDoubleClick
+ })[0].outerHTML;
+ var div = ''+a+'
';
+ return div;
+}
+
+var setup = function() {
+ $('#toolbox').append(' Portals list');
+ $('head').append('');
+ // Setup sorting
+ $(document).on('click.portalslist', '#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', '#portalslist .filterAll', function() {
+ $('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,0));
+ });
+ $(document).on('click.portalslist', '#portalslist .filterRes', function() {
+ $('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,1));
+ });
+ $(document).on('click.portalslist', '#portalslist .filterEnl', function() {
+ $('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,2));
+ });
+}
+
+// PLUGIN END //////////////////////////////////////////////////////////
+
+@@PLUGINEND@@