Merge pull request #867 from fkloft/portals-list

new framework for portals-list
This commit is contained in:
fkloft
2014-09-13 19:06:39 +02:00
8 changed files with 651 additions and 220 deletions

View File

@ -30,7 +30,7 @@
// use own namespace for plugin
window.plugin.bookmarks = function() {};
window.plugin.bookmarks.SYNC_DELAY = 5000;
window.plugin.bookmarks.SYNC_DELAY = 5;
window.plugin.bookmarks.KEY_OTHER_BKMRK = 'idOthers';
window.plugin.bookmarks.KEY_STORAGE = 'plugin-bookmarks';
@ -322,12 +322,12 @@
}
// Switch the status of the star
window.plugin.bookmarks.switchStarPortal = function() {
var guid = window.selectedPortal;
window.plugin.bookmarks.switchStarPortal = function(guid) {
if(guid == undefined) guid = window.selectedPortal;
// If portal is saved in bookmarks: Remove this bookmark
if($('.bkmrksStar').hasClass('favorite')) {
var bkmrkData = window.plugin.bookmarks.findByGuid(guid);
var bkmrkData = window.plugin.bookmarks.findByGuid(guid);
if(bkmrkData) {
var list = window.plugin.bookmarks.bkmrksObj['portals'];
delete list[bkmrkData['id_folder']]['bkmrk'][bkmrkData['id_bookmark']];
$('.bkmrk#'+bkmrkData['id_bookmark']+'').remove();
@ -342,24 +342,23 @@
else{
// Get portal name and coordinates
var p = window.portals[guid];
var d = p.options.data;
var label = d.title;
var lat = p.getLatLng().lat;
var lng = p.getLatLng().lng;
var latlng = lat+','+lng;
var ID = window.plugin.bookmarks.generateID();
// Add bookmark in the localStorage
window.plugin.bookmarks.bkmrksObj['portals'][window.plugin.bookmarks.KEY_OTHER_BKMRK]['bkmrk'][ID] = {"guid":guid,"latlng":latlng,"label":label};
window.plugin.bookmarks.saveStorage();
window.plugin.bookmarks.refreshBkmrks();
window.runHooks('pluginBkmrksEdit', {"target": "portal", "action": "add", "id": ID});
console.log('BOOKMARKS: added portal '+ID);
var ll = p.getLatLng();
plugin.bookmarks.addPortalBookmark(guid, ll.lat+','+ll.lng, p.options.data.title);
}
}
plugin.bookmarks.addPortalBookmark = function(guid, latlng, label) {
var ID = window.plugin.bookmarks.generateID();
// Add bookmark in the localStorage
window.plugin.bookmarks.bkmrksObj['portals'][window.plugin.bookmarks.KEY_OTHER_BKMRK]['bkmrk'][ID] = {"guid":guid,"latlng":latlng,"label":label};
window.plugin.bookmarks.saveStorage();
window.plugin.bookmarks.refreshBkmrks();
window.runHooks('pluginBkmrksEdit', {"target": "portal", "action": "add", "id": ID, "guid": guid});
console.log('BOOKMARKS: added portal '+ID);
}
// Add BOOKMARK/FOLDER
window.plugin.bookmarks.addElement = function(elem, type) {
var ID = window.plugin.bookmarks.generateID();
@ -1031,7 +1030,7 @@
window.plugin.bookmarks.editStar = function(data) {
if(data.target === 'portal') {
if(data.action === 'add') {
var guid = window.selectedPortal;
var guid = data.guid;
var latlng = window.portals[guid].getLatLng();
var lbl = window.portals[guid].options.data.title;
var starInLayer = window.plugin.bookmarks.starLayers[data.guid];
@ -1053,7 +1052,61 @@
window.plugin.bookmarks.setupCSS = function() {
$('<style>').prop('type', 'text/css').html('@@INCLUDESTRING:plugins/bookmarks-css.css@@').appendTo('head');
}
window.plugin.bookmarks.setupPortalsList = function() {
function onBookmarkChanged(data) {
console.log(data, data.target, data.guid);
if(data.target == "portal" && data.guid) {
if(plugin.bookmarks.findByGuid(data.guid))
$('[data-list-bookmark="'+data.guid+'"]').addClass("favorite");
else
$('[data-list-bookmark="'+data.guid+'"]').removeClass("favorite");
} else {
$('[data-list-bookmark]').each(function(i, element) {
var guid = element.getAttribute("data-list-bookmark");
if(plugin.bookmarks.findByGuid(guid))
$(element).addClass("favorite");
else
$(element).removeClass("favorite");
});
}
}
window.addHook('pluginBkmrksEdit', onBookmarkChanged);
window.addHook('pluginBkmrksSyncEnd', onBookmarkChanged);
window.plugin.portalslist.fields.unshift({ // insert at first column
title: "",
value: function(portal) { return portal.options.guid; }, // we store the guid, but implement a custom comparator so the list does sort properly without closing and reopening the dialog
sort: function(guidA, guidB) {
var infoA = plugin.bookmarks.findByGuid(guidA);
var infoB = plugin.bookmarks.findByGuid(guidB);
if(infoA && !infoB) return 1;
if(infoB && !infoA) return -1;
return 0;
},
format: function(cell, portal, guid) {
$(cell)
.addClass("portal-list-bookmark")
.attr("data-list-bookmark", guid);
// for some reason, jQuery removes event listeners when the list is sorted. Therefore we use DOM's addEventListener
$('<span>').appendTo(cell)[0].addEventListener("click", function() {
if(window.plugin.bookmarks.findByGuid(guid)) {
window.plugin.bookmarks.switchStarPortal(guid);
} else {
var ll = portal.getLatLng();
plugin.bookmarks.addPortalBookmark(guid, ll.lat+','+ll.lng, portal.options.data.title);
}
}, false);
if(plugin.bookmarks.findByGuid(guid))
cell.className += " favorite";
},
});
}
window.plugin.bookmarks.setupContent = function() {
plugin.bookmarks.htmlBoxTrigger = '<a id="bkmrksTrigger" class="open" onclick="window.plugin.bookmarks.switchStatusBkmrksBox(\'switch\');return false;" accesskey="v" title="[v]">[-] Bookmarks</a>';
plugin.bookmarks.htmlBkmrksBox = '<div id="bookmarksBox">'
@ -1179,6 +1232,15 @@
window.plugin.bookmarks.addAllStars();
window.addHook('pluginBkmrksEdit', window.plugin.bookmarks.editStar);
window.addHook('pluginBkmrksSyncEnd', window.plugin.bookmarks.resetAllStars);
if(window.plugin.portalslist) {
window.plugin.bookmarks.setupPortalsList();
} else {
setTimeout(function() {
if(window.plugin.portalslist)
window.plugin.bookmarks.setupPortalsList();
}, 500);
}
}
// PLUGIN END //////////////////////////////////////////////////////////

View File

@ -273,7 +273,16 @@
#sidebar #portaldetails h3.title{
width:auto;
}
#bkmrksTrigger, .bkmrksStar span{
.portal-list-bookmark span {
display:inline-block;
margin: -3px;
width:16px;
height:15px;
overflow:hidden;
background-repeat:no-repeat;
cursor:pointer;
}
#bkmrksTrigger, .bkmrksStar span, .portal-list-bookmark span {
background-image:url(@@INCLUDEIMAGE:plugins/bookmarks-img.png@@);
}
.bkmrksStar span{
@ -288,7 +297,7 @@
.bkmrksStar span, .bkmrksStar.favorite:focus span{
background-position:left top;
}
.bkmrksStar:focus span, .bkmrksStar.favorite span{
.bkmrksStar:focus span, .bkmrksStar.favorite span, .portal-list-bookmark.favorite span{
background-position:right top;
}
#bookmarksBox .bookmarkList .bookmarkFolder{

View File

@ -64,3 +64,23 @@
margin: 6px 3px 1px 20px !important;
cursor: help;
}
.portal-list-keys button {
font-family: monospace;
font-size: 0.9em;
text-align: center;
vertical-align: middle;
min-width: 0;
padding: 0;
width: 1.5em;
margin: -6px 0 -3px;
}
#portalslist.mobile .portal-list-keys button {
width: 3em;
height: 1.5em;
}
.portal-list-keys .plus {
margin-left: 0.3em;
margin-right: -1px;
}

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-keys@xelio
// @name IITC plugin: Keys
// @category Keys
// @version 0.2.0.@@DATETIMEVERSION@@
// @version 0.3.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -55,8 +55,9 @@ window.plugin.keys.updateDisplayCount = function() {
$('#keys-count').html(count);
}
window.plugin.keys.addKey = function(addCount) {
var guid = window.selectedPortal;
window.plugin.keys.addKey = function(addCount, guid) {
if(guid == undefined) guid = window.selectedPortal;
var oldCount = plugin.keys.keys[guid];
var newCount = Math.max((oldCount || 0) + addCount, 0);
if(oldCount !== newCount) {
@ -169,7 +170,7 @@ window.plugin.keys.setupCSS = function() {
$("<style>")
.prop("type", "text/css")
.html("@@INCLUDESTRING:plugins/keys.css@@")
.appendTo("head");
.appendTo("head");
}
window.plugin.keys.setupContent = function() {
@ -191,6 +192,52 @@ window.plugin.keys.setupContent = function() {
plugin.keys.disabledMessage = '<div id="keys-content-outer" title="Your browser do not support localStorage">Plugin Keys disabled</div>';
}
window.plugin.keys.setupPortalsList = function() {
if(!window.plugin.portalslist) return;
window.addHook('pluginKeysUpdateKey', function(data) {
$('[data-list-keycount="'+data.guid+'"]').text(data.count);
});
window.addHook('pluginKeysRefreshAll', function() {
$('[data-list-keycount]').each(function(i, element) {
var guid = element.getAttribute("data-list-keycount");
$(element).text(plugin.keys.keys[guid] || 0);
});
});
window.plugin.portalslist.fields.push({
title: "Keys",
value: function(portal) { return portal.options.guid; }, // we store the guid, but implement a custom comparator so the list does sort properly without closing and reopening the dialog
sort: function(guidA, guidB) {
var keysA = plugin.keys.keys[guidA] || 0;
var keysB = plugin.keys.keys[guidB] || 0;
return keysA - keysB;
},
format: function(cell, portal, guid) {
$(cell)
.addClass("alignR portal-list-keys ui-dialog-buttonset") // ui-dialog-buttonset for proper button styles
.append($('<span>')
.text(plugin.keys.keys[guid] || 0)
.attr({
"class": "value",
"data-list-keycount": guid
}));
// for some reason, jQuery removes event listeners when the list is sorted. Therefore we use DOM's addEventListener
$('<button>')
.text('+')
.addClass("plus")
.appendTo(cell)
[0].addEventListener("click", function() { window.plugin.keys.addKey(1, guid); }, false);
$('<button>')
.text('-')
.addClass("minus")
.appendTo(cell)
[0].addEventListener("click", function() { window.plugin.keys.addKey(-1, guid); }, false);
},
});
}
var setup = function() {
if($.inArray('pluginKeysUpdateKey', window.VALID_HOOKS) < 0)
window.VALID_HOOKS.push('pluginKeysUpdateKey');
@ -203,6 +250,15 @@ var setup = function() {
window.plugin.keys.loadKeys();
window.addHook('portalDetailsUpdated', window.plugin.keys.addToSidebar);
window.addHook('iitcLoaded', window.plugin.keys.registerFieldForSyncing);
if(window.plugin.portalslist) {
window.plugin.keys.setupPortalsList();
} else {
setTimeout(function() {
if(window.plugin.portalslist)
window.plugin.keys.setupPortalsList();
}, 500);
}
}
// PLUGIN END //////////////////////////////////////////////////////////

105
plugins/portals-list.css Normal file
View File

@ -0,0 +1,105 @@
#portalslist.mobile {
background: transparent;
border: 0 none !important;
height: 100% !important;
width: 100% !important;
left: 0 !important;
top: 0 !important;
position: absolute;
overflow: auto;
}
#portalslist table {
margin-top: 5px;
border-collapse: collapse;
empty-cells: show;
width: 100%;
clear: both;
}
#portalslist table td, #portalslist table th {
background-color: #1b415e;
border-bottom: 1px solid #0b314e;
color: white;
padding: 3px;
}
#portalslist table th {
text-align: center;
}
#portalslist table .alignR {
text-align: right;
}
#portalslist table.portals td {
white-space: nowrap;
}
#portalslist table th.sortable {
cursor: pointer;
}
#portalslist table .portalTitle {
min-width: 120px !important;
max-width: 240px !important;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#portalslist .sorted {
color: #FFCE00;
}
#portalslist table.filter {
table-layout: fixed;
cursor: pointer;
border-collapse: separate;
border-spacing: 1px;
}
#portalslist table.filter th {
text-align: left;
padding-left: 0.3em;
overflow: hidden;
text-overflow: ellipsis;
}
#portalslist table.filter td {
text-align: right;
padding-right: 0.3em;
overflow: hidden;
text-overflow: ellipsis;
}
#portalslist .filterNeu {
background-color: #666;
}
#portalslist table tr.res td, #portalslist .filterRes {
background-color: #005684;
}
#portalslist table tr.enl td, #portalslist .filterEnl {
background-color: #017f01;
}
#portalslist table tr.none td {
background-color: #000;
}
#portalslist .disclaimer {
margin-top: 10px;
font-size: 10px;
}
#portalslist.mobile table.filter tr {
display: block;
text-align: center;
}
#portalslist.mobile table.filter th, #portalslist.mobile table.filter td {
display: inline-block;
width: 22%;
}

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @category Info
// @version 0.1.2.@@DATETIMEVERSION@@
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -18,42 +18,135 @@
// PLUGIN START ////////////////////////////////////////////////////////
/* whatsnew
* 0.1.0 : 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.sortBy = 'level';
window.plugin.portalslist.sortBy = 1; // second column: level
window.plugin.portalslist.sortOrder = -1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
window.plugin.portalslist.neuP = 0;
window.plugin.portalslist.filter = 0;
/*
* plugins may add fields by appending their specifiation to the following list. The following members are supported:
* title: String
* Name of the column. Required.
* value: function(portal)
* The raw value of this field. Can by anything. Required, but can be dummy implementation if sortValue and format
* are implemented.
* sortValue: function(value, portal)
* The value to sort by. Optional, uses value if omitted. The raw value is passed as first argument.
* sort: function(valueA, valueB, portalA, portalB)
* Custom sorting function. See Array.sort() for details on return value. Both the raw values and the portal objects
* are passed as arguments. Optional. Set to null to disable sorting
* format: function(cell, portal, value)
* Used to fill and format the cell, which is given as a DOM node. If omitted, the raw value is put in the cell.
* defaultOrder: -1|1
* Which order should by default be used for this column. -1 means descending. Default: 1
*/
window.plugin.portalslist.fields = [
{
title: "Portal Name",
value: function(portal) { return portal.options.data.title; },
sortValue: function(value, portal) { return value.toLowerCase(); },
format: function(cell, portal, value) {
$(cell)
.append(plugin.portalslist.getPortalLink(portal))
.addClass("portalTitle");
}
},
{
title: "Level",
value: function(portal) { return portal.options.data.level; },
format: function(cell, portal, value) {
$(cell)
.css('background-color', COLORS_LVL[value])
.text('L' + value);
},
defaultOrder: -1,
},
{
title: "Team",
value: function(portal) { return portal.options.team; },
format: function(cell, portal, value) {
$(cell).text(['NEU', 'RES', 'ENL'][value]);
}
},
{
title: "Health",
value: function(portal) { return portal.options.data.health; },
sortValue: function(value, portal) { return portal.options.team===TEAM_NONE ? -1 : value; },
format: function(cell, portal, value) {
$(cell)
.addClass("alignR")
.text(portal.options.team===TEAM_NONE ? '-' : value+'%');
}
},
{
title: "Res",
value: function(portal) { return portal.options.data.resCount; },
format: function(cell, portal, value) {
$(cell)
.addClass("alignR")
.text(value);
}
},
{
title: "Links",
value: function(portal) { return window.getPortalLinks(portal.options.guid); },
sortValue: function(value, portal) { return value.in.length + value.out.length; },
format: function(cell, portal, value) {
$(cell)
.addClass("alignR")
.addClass('help')
.attr('title', 'In:\t' + value.in.length + '\nOut:\t' + value.out.length)
.text(value.in.length+value.out.length);
}
},
{
title: "Fields",
value: function(portal) { return getPortalFieldsCount(portal.options.guid) },
format: function(cell, portal, value) {
$(cell)
.addClass("alignR")
.text(value);
}
},
{
title: "AP",
value: function(portal) {
var links = window.getPortalLinks(portal.options.guid);
var fields = getPortalFieldsCount(portal.options.guid);
return portalApGainMaths(portal.options.data.resCount, links.in.length+links.out.length, fields);
},
sortValue: function(value, portal) { return value.enemyAp; },
format: function(cell, portal, value) {
var title = '';
if (PLAYER.team == portal.options.data.team) {
title += 'Friendly AP:\t'+value.friendlyAp+'\n'
+ '- deploy '+(8-portal.options.data.resCount)+' resonator(s)\n'
+ '- upgrades/mods unknown\n';
}
title += 'Enemy AP:\t'+value.enemyAp+'\n'
+ '- Destroy AP:\t'+value.destroyAp+'\n'
+ '- Capture AP:\t'+value.captureAp;
$(cell)
.addClass("alignR")
.addClass('help')
.prop('title', title)
.html(digits(value.enemyAp));
}
},
];
//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
//filter : 0 = All, 1 = Neutral, 2 = Res, 3 = Enl, -x = all but x
var retval=false;
var displayBounds = map.getBounds();
@ -64,64 +157,69 @@ window.plugin.portalslist.getPortals = function() {
if(!displayBounds.contains(portal.getLatLng())) return true;
retval=true;
var d = portal.options.data;
var teamN = portal.options.team;
switch (teamN) {
switch (portal.options.team) {
case TEAM_RES:
window.plugin.portalslist.resP++;
break;
case TEAM_ENL:
window.plugin.portalslist.enlP++;
break;
default:
window.plugin.portalslist.neuP++;
}
var l = window.getPortalLinks(i);
var f = window.getPortalFields(i);
var ap = portalApGainMaths(d.resCount, l.in.length+l.out.length, f.length);
var thisPortal = {
'portal': portal,
'guid': i,
'teamN': teamN, // TEAM_NONE, TEAM_RES or TEAM_ENL
'team': d.team, // "NEUTRAL", "RESISTANCE" or "ENLIGHTENED"
'name': d.title || '(untitled)',
'nameLower': d.title && d.title.toLowerCase(),
'level': portal.options.level,
'health': d.health,
'resCount': d.resCount,
'img': d.img,
'linkCount': l.in.length + l.out.length,
'link' : l,
'fieldCount': f.length,
'field' : f,
'enemyAp': ap.enemyAp,
'ap': ap,
};
window.plugin.portalslist.listPortals.push(thisPortal);
// cache values and DOM nodes
var obj = { portal: portal, values: [], sortValues: [] };
var row = document.createElement('tr');
row.className = TEAM_TO_CSS[portal.options.team];
obj.row = row;
var cell = row.insertCell(-1);
cell.className = 'alignR';
window.plugin.portalslist.fields.forEach(function(field, i) {
cell = row.insertCell(-1);
var value = field.value(portal);
obj.values.push(value);
obj.sortValues.push(field.sortValue ? field.sortValue(value, portal) : value);
if(field.format) {
field.format(cell, portal, value);
} else {
cell.textContent = value;
}
});
window.plugin.portalslist.listPortals.push(obj);
});
return retval;
}
window.plugin.portalslist.displayPL = function() {
var html = '';
window.plugin.portalslist.sortBy = 'level';
var list;
window.plugin.portalslist.sortBy = 1;
window.plugin.portalslist.sortOrder = -1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
window.plugin.portalslist.neuP = 0;
window.plugin.portalslist.filter = 0;
if (window.plugin.portalslist.getPortals()) {
html += window.plugin.portalslist.portalTable(window.plugin.portalslist.sortBy, window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter);
list = window.plugin.portalslist.portalTable(window.plugin.portalslist.sortBy, window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter);
} else {
html = '<table class="noPortals"><tr><td>Nothing to show!</td></tr></table>';
list = $('<table class="noPortals"><tr><td>Nothing to show!</td></tr></table>');
};
if(window.useAndroidPanes()) {
$('<div id="portalslist" class="mobile">' + html + '</div>').appendTo(document.body);
$('<div id="portalslist" class="mobile">').append(list).appendTo(document.body);
} else {
dialog({
html: '<div id="portalslist">' + html + '</div>',
html: $('<div id="portalslist">').append(list),
dialogClass: 'ui-dialog-portalslist',
title: 'Portal list: ' + window.plugin.portalslist.listPortals.length + ' ' + (window.plugin.portalslist.listPortals.length == 1 ? 'portal' : 'portals'),
id: 'portal-list',
@ -136,124 +234,143 @@ window.plugin.portalslist.portalTable = function(sortBy, sortOrder, filter) {
window.plugin.portalslist.sortOrder = sortOrder;
window.plugin.portalslist.filter = filter;
var portals=window.plugin.portalslist.listPortals;
var portals = window.plugin.portalslist.listPortals;
var sortField = window.plugin.portalslist.fields[sortBy];
//Array sort
window.plugin.portalslist.listPortals.sort(function(a, b) {
var retVal = 0;
portals.sort(function(a, b) {
var valueA = a.sortValues[sortBy];
var valueB = b.sortValues[sortBy];
var aComp = a[sortBy];
var bComp = b[sortBy];
if (aComp < bComp) {
retVal = -1;
} else if (aComp > bComp) {
retVal = 1;
} else {
// equal - compare GUIDs to ensure consistent (but arbitrary) order
retVal = a.guid < b.guid ? -1 : 1;
if(sortField.sort) {
return sortOrder * sortField.sort(valueA, valueB, a.portal, b.portal);
}
// sortOrder is 1 (normal) or -1 (reversed)
retVal = retVal * sortOrder;
return retVal;
return sortOrder *
(valueA < valueB ? -1 :
valueA > valueB ? 1 :
0);
});
var sortAttr = window.plugin.portalslist.portalTableHeaderSortAttr;
var html = window.plugin.portalslist.stats();
html += '<table class="portals">'
+ '<tr class="header">'
+ '<th>#</th>'
+ '<th ' + sortAttr('nameLower', sortBy, 1, 'portalTitle') + '>Portal Name</th>'
+ '<th ' + sortAttr('level', sortBy, -1) + '>Level</th>'
+ '<th ' + sortAttr('teamN', sortBy, 1) + '>Team</th>'
+ '<th ' + sortAttr('health', sortBy, -1) + '>Health</th>'
+ '<th ' + sortAttr('resCount', sortBy, -1) + '>Res</th>'
+ '<th ' + sortAttr('linkCount', sortBy, -1) + '>Links</th>'
+ '<th ' + sortAttr('fieldCount', sortBy, -1) + '>Fields</th>'
+ '<th ' + sortAttr('enemyAp', sortBy, -1) + '>AP</th>'
+ '</tr>\n';
if(filter !== 0) {
portals = portals.filter(function(obj) {
return filter < 0
? obj.portal.options.team+1 != -filter
: obj.portal.options.team+1 == filter;
});
}
var rowNum = 1;
var table, row, cell;
var container = $('<div>');
$.each(portals, function(ind, portal) {
if (filter === TEAM_NONE || filter === portal.teamN) {
table = document.createElement('table');
table.className = 'filter';
container.append(table);
html += '<tr class="' + (portal.teamN === window.TEAM_RES ? 'res' : (portal.teamN === window.TEAM_ENL ? 'enl' : 'neutral')) + '">'
+ '<td>'+rowNum+'</td>'
+ '<td class="portalTitle" style="">' + window.plugin.portalslist.getPortalLink(portal, portal.guid) + '</td>'
+ '<td class="L' + portal.level +'" style="background-color: '+COLORS_LVL[portal.level]+'">' + portal.level + '</td>'
+ '<td style="text-align:center;">' + portal.team.substr(0,3) + '</td>';
row = table.insertRow(-1);
html += '<td>' + (portal.teamN!=TEAM_NONE?portal.health+'%':'-') + '</td>'
+ '<td>' + portal.resCount + '</td>'
+ '<td class="help" title="In: ' + portal.link.in.length + ' Out: ' + portal.link.out.length + '">' + (portal.linkCount?portal.linkCount:'-') + '</td>'
+ '<td>' + (portal.fieldCount?portal.fieldCount:'-') + '</td>';
var length = window.plugin.portalslist.listPortals.length;
var apTitle = '';
if (PLAYER.team == portal.team) {
apTitle += 'Friendly AP:\t'+portal.ap.friendlyAp+'\n'
+ '- deploy '+(8-portal.resCount)+' resonator(s)\n'
+ '- upgrades/mods unknown\n';
["All", "Neutral", "Resistance", "Enlightened"].forEach(function(label, i) {
cell = row.appendChild(document.createElement('th'));
cell.className = 'filter' + label.substr(0, 3);
cell.textContent = label+':';
cell.title = 'Show only portals of this color';
$(cell).click(function() {
$('#portalslist').empty().append(window.plugin.portalslist.portalTable(sortBy, sortOrder, i));
});
cell = row.insertCell(-1);
cell.className = 'filter' + label.substr(0, 3);
if(i != 0) cell.title = 'Hide portals of this color';
$(cell).click(function() {
$('#portalslist').empty().append(window.plugin.portalslist.portalTable(sortBy, sortOrder, -i));
});
switch(i-1) {
case -1:
cell.textContent = length;
break;
case 0:
cell.textContent = window.plugin.portalslist.neuP + ' (' + Math.round(window.plugin.portalslist.neuP/length*100) + '%)';
break;
case 1:
cell.textContent = window.plugin.portalslist.resP + ' (' + Math.round(window.plugin.portalslist.resP/length*100) + '%)';
break;
case 2:
cell.textContent = window.plugin.portalslist.enlP + ' (' + Math.round(window.plugin.portalslist.enlP/length*100) + '%)';
}
});
table = document.createElement('table');
table.className = 'portals';
container.append(table);
var thead = table.appendChild(document.createElement('thead'));
row = thead.insertRow(-1);
cell = row.appendChild(document.createElement('th'));
cell.textContent = '#';
window.plugin.portalslist.fields.forEach(function(field, i) {
cell = row.appendChild(document.createElement('th'));
cell.textContent = field.title;
if(field.sort !== null) {
cell.classList.add("sortable");
if(i == window.plugin.portalslist.sortBy) {
cell.classList.add("sorted");
}
apTitle += 'Enemy AP:\t'+portal.ap.enemyAp+'\n'
+ '- Destroy AP:\t'+portal.ap.destroyAp+'\n'
+ '- Capture AP:\t'+portal.ap.captureAp;
html += '<td class="help apGain" title="' + apTitle + '">' + digits(portal.ap.enemyAp) + '</td>';
$(cell).click(function() {
var order;
if(i == sortBy) {
order = -sortOrder;
} else {
order = field.defaultOrder < 0 ? -1 : 1;
}
html+= '</tr>';
rowNum++;
$('#portalslist').empty().append(window.plugin.portalslist.portalTable(i, order, filter));
});
}
});
html += '</table>';
html += '<div class="disclaimer">Click on portals table headers to sort by that column. '
+ 'Click on <b>All Portals, Resistance Portals, Enlightened Portals</b> to filter</div>';
portals.forEach(function(obj, i) {
var row = obj.row
if(row.parentNode) row.parentNode.removeChild(row);
return html;
row.cells[0].textContent = i+1;
table.appendChild(row);
});
container.append('<div class="disclaimer">Click on portals table headers to sort by that column. '
+ 'Click on <b>All, Neutral, Resistance, Enlightened</b> to only show portals owner by that faction or on the number behind the factions to show all but those portals.</div>');
return container;
}
window.plugin.portalslist.stats = function(sortBy) {
var html = '<table class="teamFilter"><tr>'
+ '<td class="filterAll" style="cursor:pointer"><a href=""></a>All Portals : (click to filter)</td><td class="filterAll">' + window.plugin.portalslist.listPortals.length + '</td>'
+ '<td class="filterRes" style="cursor:pointer" class="sorted">Resistance Portals : </td><td class="filterRes">' + window.plugin.portalslist.resP +' (' + Math.floor(window.plugin.portalslist.resP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '<td class="filterEnl" style="cursor:pointer" class="sorted">Enlightened Portals : </td><td class="filterEnl">'+ window.plugin.portalslist.enlP +' (' + Math.floor(window.plugin.portalslist.enlP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '</tr>'
+ '</table>';
return html;
}
// A little helper function so the above isn't so messy
window.plugin.portalslist.portalTableHeaderSortAttr = function(name, by, defOrder, extraClass) {
// data-sort attr: used by jquery .data('sort') below
var retVal = 'data-sort="'+name+'" data-defaultorder="'+defOrder+'" class="'+(extraClass?extraClass+' ':'')+'sortable'+(name==by?' 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 coord = portal.portal.getLatLng();
var latlng = [coord.lat, coord.lng].join();
var jsSingleClick = 'window.renderPortalDetails(\''+guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
window.plugin.portalslist.getPortalLink = function(portal) {
var coord = portal.getLatLng();
var perma = '/intel?ll='+coord.lat+','+coord.lng+'&z=17&pll='+coord.lat+','+coord.lng;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('<a>',{
text: portal.name,
// title: portal.name,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
return a;
// jQuery's event handlers seem to be removed when the nodes are remove from the DOM
var link = document.createElement("a");
link.textContent = portal.options.data.title;
link.href = perma;
link.addEventListener("click", function(ev) {
renderPortalDetails(portal.options.guid);
ev.preventDefault();
return false;
}, false);
link.addEventListener("dblclick", function(ev) {
zoomToAndShowPortal(portal.options.guid, [coord.lat, coord.lng]);
ev.preventDefault();
return false;
});
return link;
}
window.plugin.portalslist.onPaneChanged = function(pane) {
@ -271,45 +388,11 @@ var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.portalslist.displayPL()" title="Display a list of portals in the current view">Portals list</a>');
}
$('head').append('<style>' +
'#portalslist.mobile {background: transparent; border: 0 none !important; height: 100% !important; width: 100% !important; left: 0 !important; top: 0 !important; position: absolute; overflow: auto; }' +
'#portalslist table { margin-top:5px; border-collapse: collapse; empty-cells: show; width: 100%; clear: both; }' +
'#portalslist table td, #portalslist table th {border-bottom: 1px solid #0b314e; padding:3px; color:white; background-color:#1b415e}' +
'#portalslist table tr.res td { background-color: #005684; }' +
'#portalslist table tr.enl td { background-color: #017f01; }' +
'#portalslist table tr.neutral td { background-color: #000000; }' +
'#portalslist table th { text-align: center; }' +
'#portalslist table td { text-align: center; }' +
'#portalslist table.portals td { white-space: nowrap; }' +
'#portalslist table td.portalTitle { text-align: left;}' +
'#portalslist table th.sortable { cursor:pointer;}' +
'#portalslist table th.portalTitle { text-align: left;}' +
'#portalslist table .portalTitle { min-width: 120px !important; max-width: 240px !important; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }' +
'#portalslist table .apGain { text-align: right !important; }' +
'#portalslist .sorted { color:#FFCE00; }' +
'#portalslist .filterAll { margin-top: 10px;}' +
'#portalslist .filterRes { margin-top: 10px; background-color: #005684 }' +
'#portalslist .filterEnl { margin-top: 10px; background-color: #017f01 }' +
'#portalslist .disclaimer { margin-top: 10px; font-size:10px; }' +
'</style>');
$("<style>")
.prop("type", "text/css")
.html("@@INCLUDESTRING:plugins/portals-list.css@@")
.appendTo("head");
// Setup sorting
$(document).on('click.portalslist', '#portalslist table th.sortable', function() {
var sortBy = $(this).data('sort');
// if this is the currently selected column, toggle the sort order - otherwise use the columns default sort order
var sortOrder = sortBy == window.plugin.portalslist.sortBy ? window.plugin.portalslist.sortOrder*-1 : parseInt($(this).data('defaultorder'));
$('#portalslist').html(window.plugin.portalslist.portalTable(sortBy,sortOrder,window.plugin.portalslist.filter));
});
$(document).on('click.portalslist', '#portalslist .filterAll', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable(window.plugin.portalslist.sortBy,window.plugin.portalslist.sortOrder,0));
});
$(document).on('click.portalslist', '#portalslist .filterRes', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable(window.plugin.portalslist.sortBy,window.plugin.portalslist.sortOrder,1));
});
$(document).on('click.portalslist', '#portalslist .filterEnl', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable(window.plugin.portalslist.sortBy,window.plugin.portalslist.sortOrder,2));
});
}
// PLUGIN END //////////////////////////////////////////////////////////

View File

@ -11,3 +11,9 @@
vertical-align: middle;
}
.portal-list-uniques input[type='checkbox'] {
padding: 0;
height: auto;
margin-top: -5px;
margin-bottom: -5px;
}

View File

@ -159,6 +159,8 @@ window.plugin.uniques.onPublicChatDataAvailable = function(data) {
}
window.plugin.uniques.updateCheckedAndHighlight = function(guid) {
runHooks('pluginUniquesUpdateUniques', { guid: guid });
if (guid == window.selectedPortal) {
var uniqueInfo = plugin.uniques.uniques[guid];
@ -207,8 +209,9 @@ window.plugin.uniques.setPortalCaptured = function(guid) {
plugin.uniques.sync(guid);
}
window.plugin.uniques.updateVisited = function(visited) {
var guid = window.selectedPortal;
window.plugin.uniques.updateVisited = function(visited, guid) {
if(guid == undefined) guid = window.selectedPortal;
var uniqueInfo = plugin.uniques.uniques[guid];
if (!uniqueInfo) {
plugin.uniques.uniques[guid] = uniqueInfo = {
@ -228,8 +231,9 @@ window.plugin.uniques.updateVisited = function(visited) {
plugin.uniques.sync(guid);
}
window.plugin.uniques.updateCaptured = function(captured) {
var guid = window.selectedPortal;
window.plugin.uniques.updateCaptured = function(captured, guid) {
if(guid == undefined) guid = window.selectedPortal;
var uniqueInfo = plugin.uniques.uniques[guid];
if (!uniqueInfo) {
plugin.uniques.uniques[guid] = uniqueInfo = {
@ -401,6 +405,83 @@ window.plugin.uniques.setupContent = function() {
plugin.uniques.disabledMessage = '<div id="uniques-container" class="help" title="Your browser does not support localStorage">Plugin Uniques disabled</div>';
}
window.plugin.uniques.setupPortalsList = function() {
if(!window.plugin.portalslist) return;
window.addHook('pluginUniquesUpdateUniques', function(data) {
var info = plugin.uniques.uniques[data.guid];
if(!info) info = { visited: false, captured: false };
$('[data-list-uniques="'+data.guid+'"].visited').prop('checked', !!info.visited);
$('[data-list-uniques="'+data.guid+'"].captured').prop('checked', !!info.captured);
});
window.addHook('pluginUniquesRefreshAll', function() {
$('[data-list-uniques]').each(function(i, element) {
var guid = element.getAttribute("data-list-uniques");
var info = plugin.uniques.uniques[guid];
if(!info) info = { visited: false, captured: false };
var e = $(element);
if(e.hasClass('visited')) e.prop('checked', !!info.visited);
if(e.hasClass('captured')) e.prop('checked', !!info.captured);
});
});
function uniqueValue(guid) {
var info = plugin.uniques.uniques[guid];
if(!info) return 0;
if(info.visited && info.captured) return 2;
if(info.visited) return 1;
}
window.plugin.portalslist.fields.push({
title: "Visit",
value: function(portal) { return portal.options.guid; }, // we store the guid, but implement a custom comparator so the list does sort properly without closing and reopening the dialog
sort: function(guidA, guidB) {
return uniqueValue(guidA) - uniqueValue(guidB);
},
format: function(cell, portal, guid) {
var info = plugin.uniques.uniques[guid];
if(!info) info = { visited: false, captured: false };
$(cell).addClass("portal-list-uniques");
// for some reason, jQuery removes event listeners when the list is sorted. Therefore we use DOM's addEventListener
$('<input>')
.prop({
type: "checkbox",
className: "visited",
title: "Portal visited?",
checked: !!info.visited,
})
.attr("data-list-uniques", guid)
.appendTo(cell)
[0].addEventListener("change", function(ev) {
window.plugin.uniques.updateVisited(this.checked, guid);
ev.preventDefault();
return false;
}, false);
$('<input>')
.prop({
type: "checkbox",
className: "captured",
title: "Portal captured?",
checked: !!info.captured,
})
.attr("data-list-uniques", guid)
.appendTo(cell)
[0].addEventListener("change", function(ev) {
window.plugin.uniques.updateCaptured(this.checked, guid);
ev.preventDefault();
return false;
}, false);
},
});
}
var setup = function() {
if($.inArray('pluginUniquesUpdateUniques', window.VALID_HOOKS) < 0)
window.VALID_HOOKS.push('pluginUniquesUpdateUniques');
@ -413,6 +494,15 @@ var setup = function() {
//window.addHook('publicChatDataAvailable', window.plugin.uniques.onPublicChatDataAvailable);
window.addHook('iitcLoaded', window.plugin.uniques.registerFieldForSyncing);
window.addPortalHighlighter('Uniques', window.plugin.uniques.highlighter);
if(window.plugin.portalslist) {
window.plugin.uniques.setupPortalsList();
} else {
setTimeout(function() {
if(window.plugin.portalslist)
window.plugin.uniques.setupPortalsList();
}, 500);
}
}
//PLUGIN END //////////////////////////////////////////////////////////