// PORTAL DETAILS MAIN ///////////////////////////////////////////////
// main code block that renders the portal details in the sidebar and
// methods that highlight the portal in the map view.
window.renderPortalDetails = function(guid) {
selectPortal(window.portals[guid] ? guid : null);
if(!window.portals[guid]) {
urlPortal = guid;
$('#portaldetails').html('');
if(isSmartphone()) {
$('.fullimg').remove();
$('#mobileinfo').html('');
}
return;
}
var d = window.portals[guid].options.details;
// collect some random data that’s not worth to put in an own method
var links = {incoming: 0, outgoing: 0};
if(d.portalV2.linkedEdges) $.each(d.portalV2.linkedEdges, function(ind, link) {
links[link.isOrigin ? 'outgoing' : 'incoming']++;
});
function linkExpl(t) { return ''+t+''; }
var linksText = [linkExpl('links'), linkExpl(' ↳ ' + links.incoming+' • '+links.outgoing+' ↴')];
var player = d.captured && d.captured.capturingPlayerId
? '' + getPlayerName(d.captured.capturingPlayerId) + ''
: null;
var playerText = player ? ['owner', player] : null;
var time = d.captured
? ''
+ unixTimeToString(d.captured.capturedTime) + ''
: null;
var sinceText = time ? ['since', time] : null;
var linkedFields = ['fields', d.portalV2.linkedFields ? d.portalV2.linkedFields.length : 0];
// collect and html-ify random data
var randDetails = [
playerText, sinceText,
getRangeText(d), getEnergyText(d),
linksText, getAvgResoDistText(d),
linkedFields, getAttackApGainText(d),
getHackDetailsText(d), getMitigationText(d)
];
// artifact details
//niantic hard-code the fact it's just jarvis shards/targets - so until more examples exist, we'll do the same
//(at some future point we can iterate through all the artifact types and add rows as needed)
var jarvisArtifact = artifact.getPortalData (guid, 'jarvis');
if (jarvisArtifact) {
// the genFourColumnTable function below doesn't handle cases where one column is null and the other isn't - so default to *someting* in both columns
var target = ['',''], shards = ['shards','(none)'];
if (jarvisArtifact.target) {
target = ['target', ''+(jarvisArtifact.target==TEAM_RES?'Resistance':'Enlightened')+''];
}
if (jarvisArtifact.fragments) {
shards = [jarvisArtifact.fragments.length>1?'shards':'shard', '#'+jarvisArtifact.fragments.join(', #')];
}
randDetails.push (target, shards);
}
randDetails = '
' + genFourColumnTable(randDetails) + '
';
var resoDetails = '' + getResonatorDetails(d) + '
';
var img = getPortalImageUrl(d);
var lat = d.locationE6.latE6/1E6;
var lng = d.locationE6.lngE6/1E6;
var perma = '/intel?ll='+lat+','+lng+'&z=17&pll='+lat+','+lng;
var imgTitle = 'title="'+getPortalDescriptionFromDetails(d)+'\n\nClick to show full image."';
var poslinks = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(d.portalV2.descriptiveText.TITLE)+'\')';
var portalDetailObj = window.getPortalDescriptionFromDetailsExtended(d);
var portalDetailedDescription = '';
if(portalDetailObj) {
portalDetailedDescription = '';
// TODO (once the data supports it) - portals can have multiple photos. display all, with navigation between them
// (at this time the data isn't returned from the server - although a count of images IS returned!)
if(portalDetailObj.submitter.name.length > 0) {
if(portalDetailObj.submitter.team) {
submitterSpan = '';
} else {
submitterSpan = '';
}
portalDetailedDescription += 'Photo by: | ' + submitterSpan
+ escapeHtmlSpecialChars(portalDetailObj.submitter.name) + ''+(portalDetailObj.submitter.voteCount !== undefined ? ' (' + portalDetailObj.submitter.voteCount + ' votes)' : '')+' |
';
}
if(portalDetailObj.submitter.link.length > 0) {
portalDetailedDescription += 'Photo from: | ' + escapeHtmlSpecialChars(portalDetailObj.submitter.link) + ' |
';
}
if(portalDetailObj.description) {
portalDetailedDescription += 'Description: | ' + escapeHtmlSpecialChars(portalDetailObj.description) + ' |
';
}
// if(d.portalV2.descriptiveText.ADDRESS) {
// portalDetailedDescription += 'Address: | ' + escapeHtmlSpecialChars(d.portalV2.descriptiveText.ADDRESS) + ' |
';
// }
portalDetailedDescription += '
';
}
var levelDetails = getPortalLevel(d);
if(levelDetails != 8) {
if(levelDetails==Math.ceil(levelDetails))
levelDetails += "\n8";
else
levelDetails += "\n" + (Math.ceil(levelDetails) - levelDetails)*8;
levelDetails += " resonator level(s) needed for next portal level";
} else {
levelDetails += "\nfully upgraded";
}
levelDetails = "Level " + levelDetails;
$('#portaldetails')
.attr('class', TEAM_TO_CSS[getTeam(d)])
.html(''
+ ''+escapeHtmlSpecialChars(d.portalV2.descriptiveText.TITLE)+'
'
+ 'X'
// help cursor via ".imgpreview img"
+ ''
+ '
'+Math.floor(getPortalLevel(d))+''
+ '
'+ portalDetailedDescription + '
'
+ '

'
+ ''
+ ''+getModDetails(d)+'
'
+ randDetails
+ resoDetails
+ ''
+ (
typeof android !== 'undefined' && android && android.intentPosLink // Android handles both links via a dialog
? '
'
: '
'
+ '
'
)
+ '
'
);
// try to resolve names that were required for above functions, but
// weren't available yet.
resolvePlayerNames();
runHooks('portalDetailsUpdated', {portalDetails: d});
}
// draws link-range and hack-range circles around the portal with the
// given details. Clear them if parameter 'd' is null.
window.setPortalIndicators = function(d) {
if(portalRangeIndicator) map.removeLayer(portalRangeIndicator);
portalRangeIndicator = null;
if(portalAccessIndicator) map.removeLayer(portalAccessIndicator);
portalAccessIndicator = null;
if(d === null) return;
var range = getPortalRange(d);
var coord = [d.locationE6.latE6/1E6, d.locationE6.lngE6/1E6];
portalRangeIndicator = (range.range > 0
? L.geodesicCircle(coord, range.range, {
fill: false,
color: RANGE_INDICATOR_COLOR,
weight: 3,
dashArray: range.isLinkable ? undefined : "10,10",
clickable: false })
: L.circle(coord, range.range, { fill: false, stroke: false, clickable: false })
).addTo(map);
portalAccessIndicator = L.circle(coord, HACK_RANGE,
{ fill: false, color: ACCESS_INDICATOR_COLOR, weight: 2, clickable: false }
).addTo(map);
}
// highlights portal with given GUID. Automatically clears highlights
// on old selection. Returns false if the selected portal changed.
// Returns true if it's still the same portal that just needs an
// update.
window.selectPortal = function(guid) {
var update = selectedPortal === guid;
var oldPortalGuid = selectedPortal;
selectedPortal = guid;
var oldPortal = portals[oldPortalGuid];
var newPortal = portals[guid];
// Restore style of unselected portal
if(!update && oldPortal) setMarkerStyle(oldPortal,false);
// Change style of selected portal
if(newPortal) {
setMarkerStyle(newPortal, true);
if (map.hasLayer(newPortal)) {
newPortal.bringToFront();
}
}
setPortalIndicators(newPortal ? newPortal.options.details : null);
runHooks('portalSelected', {selectedPortalGuid: guid, unselectedPortalGuid: oldPortalGuid});
return update;
}