merged upstream changes

This commit is contained in:
Cameron Moon
2013-02-11 10:06:40 +11:00
12 changed files with 283 additions and 48 deletions

View File

@ -94,7 +94,22 @@ window.setupMap = function() {
map.attributionControl.setPrefix('');
// listen for changes and store them in cookies
map.on('moveend', window.storeMapPosition);
map.on('zoomend', window.storeMapPosition);
map.on('zoomend', function() {
window.storeMapPosition;
// remove all resonators if zoom out to < RESONATOR_DISPLAY_ZOOM_LEVEL
if(isResonatorsShow()) return;
for(var i = 1; i < portalsLayers.length; i++) {
portalsLayers[i].eachLayer(function(item) {
var itemGuid = item.options.guid;
// check if 'item' is a resonator
if(getTypeByGuid(itemGuid) != TYPE_RESONATOR) return true;
portalsLayers[i].removeLayer(item);
});
}
console.log('Remove all resonators');
});
$("[name='leaflet-base-layers']").change(function () {
writeCookie('ingress.intelmap.type', $(this).parent().index());
});

View File

@ -456,7 +456,7 @@ window.chat.renderMsg = function(msg, nick, time, team) {
var t = '<time title="'+tb+'" data-timestamp="'+time+'">'+ta+'</time>';
var s = 'style="color:'+COLORS[team]+'"';
var title = nick.length >= 8 ? 'title="'+nick+'" class="help"' : '';
return '<p>'+t+'<mark '+s+'>'+nick+'</mark><span>'+msg+'</span></p>';
return '<p>'+t+'<span class="invisibleseparator"> &lt;</span><mark '+s+'>'+nick+'</mark><span class="invisibleseparator">&gt; </span><span>'+msg+'</span></p>';
}

47
code/hooks.js Normal file
View File

@ -0,0 +1,47 @@
// PLUGIN HOOKS ////////////////////////////////////////////////////////
// Plugins may listen to any number of events by specifying the name of
// the event to listen to and handing a function that should be exe-
// cuted when an event occurs. Callbacks will receive additional data
// the event created as their first parameter. The value is always a
// hash that contains more details.
//
// For example, this line will listen for portals to be added and print
// the data generated by the event to the console:
// window.addHook('portalAdded', function(data) { console.log(data) });
//
// Boot hook: booting is handled differently because IITC may not yet
// be available. Have a look at the plugins in plugins/. All
// code before “// PLUGIN START” and after “// PLUGIN END” os
// required to successfully boot the plugin.
//
// Heres more specific information about each event:
// portalAdded: called when a portal has been received and is about to
// be added to its layer group. Note that this does NOT
// mean it is already visible or will be, shortly after.
// If a portal is added to a hidden layer it may never be
// shown at all. Injection point is in
// code/map_data.js#renderPortal near the end. Will hand
// the Leaflet CircleMarker for the portal in "portal" var.
window._hooks = {}
window.VALID_HOOKS = ['portalAdded'];
window.runHooks = function(event, data) {
if(VALID_HOOKS.indexOf(event) === -1) throw('Unknown event type: ' + event);
if(!_hooks[event]) return;
$.each(_hooks[event], function(ind, callback) {
callback(data);
});
}
window.addHook = function(event, callback) {
if(VALID_HOOKS.indexOf(event) === -1) throw('Unknown event type: ' + event);
if(typeof callback !== 'function') throw('Callback must be a function.');
if(!_hooks[event])
_hooks[event] = [callback];
else
_hooks[event].push(callback);
}

View File

@ -123,7 +123,11 @@ window.handleDataResponse = function(data, textStatus, jqXHR) {
});
$.each(ppp, function(ind, portal) { renderPortal(portal); });
if(portals[selectedPortal]) portals[selectedPortal].bringToFront();
if(portals[selectedPortal]) {
try {
portals[selectedPortal].bringToFront();
} catch(e) { /* portal is now visible, catch Leaflet error */ }
}
if(portalInUrlAvailable) {
renderPortalDetails(urlPortal);
@ -142,13 +146,16 @@ window.cleanUp = function() {
var minlvl = getMinPortalLevel();
for(var i = 0; i < portalsLayers.length; i++) {
// i is also the portal level
portalsLayers[i].eachLayer(function(portal) {
portalsLayers[i].eachLayer(function(item) {
var itemGuid = item.options.guid;
// check if 'item' is a portal
if(getTypeByGuid(itemGuid) != TYPE_PORTAL) return true;
// portal must be in bounds and have a high enough level. Also dont
// remove if it is selected.
if(portal.options.guid == window.selectedPortal ||
(b.contains(portal.getLatLng()) && i >= minlvl)) return;
if(itemGuid == window.selectedPortal ||
(b.contains(item.getLatLng()) && i >= minlvl)) return true;
cnt[0]++;
portalsLayers[i].removeLayer(portal);
portalsLayers[i].removeLayer(item);
});
}
linksLayer.eachLayer(function(link) {
@ -182,6 +189,12 @@ window.removeByGuid = function(guid) {
if(!window.fields[guid]) return;
fieldsLayer.removeLayer(window.fields[guid]);
break;
case TYPE_RESONATOR:
if(!window.resonators[guid]) return;
var r = window.resonators[guid];
for(var i = 1; i < portalsLayers.length; i++)
portalsLayers[i].removeLayer(r);
break;
default:
console.warn('unknown GUID type: ' + guid);
//window.debug.printStackTrace();
@ -192,45 +205,62 @@ window.removeByGuid = function(guid) {
// renders a portal on the map from the given entity
window.renderPortal = function(ent) {
removeByGuid(ent[0]);
if(Object.keys(portals).length >= MAX_DRAWN_PORTALS && ent[0] != selectedPortal)
return;
var latlng = [ent[2].locationE6.latE6/1E6, ent[2].locationE6.lngE6/1E6];
// needs to be checked before, so the portal isnt added to the
// details list and other places
//if(!getPaddedBounds().contains(latlng)) return;
return removeByGuid(ent[0]);
// hide low level portals on low zooms
var portalLevel = getPortalLevel(ent[2]);
if(portalLevel < getMinPortalLevel() && ent[0] != selectedPortal) return;
// pre-load player names for high zoom levels
if(map.getZoom() >= PRECACHE_PLAYER_NAMES_ZOOM) {
if(ent[2].captured && ent[2].captured.capturingPlayerId)
getPlayerName(ent[2].captured.capturingPlayerId);
if(ent[2].resonatorArray && ent[2].resonatorArray.resonators)
$.each(ent[2].resonatorArray.resonators, function(ind, reso) {
if(reso) getPlayerName(reso.ownerGuid);
});
}
if(portalLevel < getMinPortalLevel() && ent[0] != selectedPortal)
return removeByGuid(ent[0]);
var team = getTeam(ent[2]);
// do nothing if portal did not change
var old = window.portals[ent[0]];
if(old && old.options.level === portalLevel && old.options.team === team)
return;
// there were changes, remove old portal
removeByGuid(ent[0]);
var latlng = [ent[2].locationE6.latE6/1E6, ent[2].locationE6.lngE6/1E6];
// pre-loads player names for high zoom levels
loadPlayerNamesForPortal(ent[2]);
var lvWeight = Math.max(2, portalLevel / 1.5);
var lvRadius = portalLevel + 3;
var p = L.circleMarker(latlng, {
radius: 7,
radius: lvRadius,
color: ent[0] == selectedPortal ? COLOR_SELECTED_PORTAL : COLORS[team],
opacity: 1,
weight: 3,
weight: lvWeight,
fillColor: COLORS[team],
fillOpacity: 0.5,
clickable: true,
level: portalLevel,
team: team,
details: ent[2],
guid: ent[0]});
p.on('remove', function() { delete window.portals[this.options.guid]; });
p.on('remove', function() {
var portalGuid = this.options.guid
// remove attached resonators, skip if
// all resonators have already removed by zooming
if(isResonatorsShow()) {
for(var i = 0; i <= 7; i++)
removeByGuid(portalResonatorGuid(portalGuid,i));
}
delete window.portals[portalGuid];
if(window.selectedPortal === portalGuid) {
window.unselectOldPortal();
window.map.removeLayer(window.portalAccessIndicator);
window.portalAccessIndicator = null;
}
});
p.on('add', function() {
window.portals[this.options.guid] = this;
// handles the case where a selected portal gets removed from the
@ -243,10 +273,71 @@ window.renderPortal = function(ent) {
window.renderPortalDetails(ent[0]);
window.map.setView(latlng, 17);
});
window.renderResonators(ent);
window.runHooks('portalAdded', {portal: p});
// portalLevel contains a float, need to round down
p.addTo(portalsLayers[parseInt(portalLevel)]);
}
window.renderResonators = function(ent) {
var portalLevel = getPortalLevel(ent[2]);
if(portalLevel < getMinPortalLevel() && ent[0] != selectedPortal) return;
if(!isResonatorsShow()) return;
for(var i=0; i < ent[2].resonatorArray.resonators.length; i++) {
var rdata = ent[2].resonatorArray.resonators[i];
if(rdata == null) continue;
if(window.resonators[portalResonatorGuid(ent[0],i)]) continue;
// offset in meters
var dn = rdata.distanceToPortal*SLOT_TO_LAT[rdata.slot];
var de = rdata.distanceToPortal*SLOT_TO_LNG[rdata.slot];
// Coordinate offset in radians
var dLat = dn/EARTH_RADIUS;
var dLon = de/(EARTH_RADIUS*Math.cos(Math.PI/180*(ent[2].locationE6.latE6/1E6)));
// OffsetPosition, decimal degrees
var lat0 = ent[2].locationE6.latE6/1E6 + dLat * 180/Math.PI;
var lon0 = ent[2].locationE6.lngE6/1E6 + dLon * 180/Math.PI;
var Rlatlng = [lat0, lon0];
var r = L.circleMarker(Rlatlng, {
radius: 3,
// #AAAAAA outline seems easier to see the fill opacity
color: '#AAAAAA',
opacity: 1,
weight: 1,
fillColor: COLORS_LVL[rdata.level],
fillOpacity: rdata.energyTotal/RESO_NRG[rdata.level],
clickable: false,
level: rdata.level,
details: rdata,
pDetails: ent[2],
guid: portalResonatorGuid(ent[0],i) });
r.on('remove', function() { delete window.resonators[this.options.guid]; });
r.on('add', function() { window.resonators[this.options.guid] = this; });
r.addTo(portalsLayers[parseInt(portalLevel)]);
}
}
// append portal guid with -resonator-[slot] to get guid for resonators
window.portalResonatorGuid = function(portalGuid, slot) {
return portalGuid + '-resonator-' + slot;
}
window.isResonatorsShow = function() {
return map.getZoom() >= RESONATOR_DISPLAY_ZOOM_LEVEL;
}
window.portalResetColor = function(portal) {
portal.setStyle({color: portal.options.fillColor});
}
@ -274,8 +365,11 @@ window.renderLink = function(ent) {
if(!getPaddedBounds().intersects(poly.getBounds())) return;
poly.on('remove', function() { delete window.links[this.options.guid]; });
poly.on('add', function() { window.links[this.options.guid] = this; });
poly.addTo(linksLayer).bringToBack();
poly.on('add', function() {
window.links[this.options.guid] = this;
this.bringToBack();
});
poly.addTo(linksLayer);
}
// renders a field on the map from a given entity
@ -302,6 +396,9 @@ window.renderField = function(ent) {
if(!getPaddedBounds().intersects(poly.getBounds())) return;
poly.on('remove', function() { delete window.fields[this.options.guid]; });
poly.on('add', function() { window.fields[this.options.guid] = this; });
poly.addTo(fieldsLayer).bringToBack();
poly.on('add', function() {
window.fields[this.options.guid] = this;
this.bringToBack();
});
poly.addTo(fieldsLayer);
}

View File

@ -46,3 +46,18 @@ window.resolvePlayerNames = function() {
window.setPlayerName = function(guid, nick) {
localStorage[guid] = nick;
}
window.loadPlayerNamesForPortal = function(portal_details) {
if(map.getZoom() < PRECACHE_PLAYER_NAMES_ZOOM) return;
var e = portal_details;
if(e.captured && e.captured.capturingPlayerId)
getPlayerName(e.captured.capturingPlayerId);
if(!e.resonatorArray || !e.resonatorArray.resonators) return;
$.each(e.resonatorArray.resonators, function(ind, reso) {
if(reso) getPlayerName(reso.ownerGuid);
});
}

View File

@ -70,7 +70,7 @@ window.renderPortalDetails = function(guid) {
+ '<div id="resodetails">'+getResonatorDetails(d)+'</div>'
+ '<div class="linkdetails">'
+ '<aside><a href="'+perma+'">portal link</a></aside>'
+ '<aside><a onclick="window.reportPortalIssue(\''+getReportIssueInfoText(d)+'\')">report issue</a></aside>'
+ '<aside><a onclick="window.reportPortalIssue()">report issue</a></aside>'
+ '</div>'
);
}

View File

@ -78,14 +78,6 @@ window.getAvgResoDistText = function(d) {
return '⌀ res dist: ' + avgDist + 'm';
}
window.getReportIssueInfoText = function(d) {
return ('Your Nick: '+PLAYER.nickname+' '
+ 'Portal: '+d.portalV2.descriptiveText.TITLE+' '
+ 'Location: '+d.portalV2.descriptiveText.ADDRESS
+' (lat '+(d.locationE6.latE6/1E6)+'; lng '+(d.locationE6.lngE6/1E6)+')'
).replace(/['"]/, '');
}
window.getResonatorDetails = function(d) {
console.log('rendering reso details');
var resoDetails = '';

View File

@ -93,6 +93,13 @@ window.rangeLinkClick = function() {
window.reportPortalIssue = function(info) {
var t = 'Redirecting you to a Google Help Page. Once there, click on “Contact Us” in the upper right corner.\n\nThe text box contains all necessary information. Press CTRL+C to copy it.';
var d = window.portals[window.selectedPortal].options.details;
var info = 'Your Nick: ' + PLAYER.nickname + ' '
+ 'Portal: ' + d.portalV2.descriptiveText.TITLE + ' '
+ 'Location: ' + d.portalV2.descriptiveText.ADDRESS
+' (lat ' + (d.locationE6.latE6/1E6) + '; lng ' + (d.locationE6.lngE6/1E6) + ')';
//codename, approx addr, portalname
if(prompt(t, info) !== null)
location.href = 'https://support.google.com/ingress?hl=en';
@ -134,8 +141,13 @@ window.scrollBottom = function(elm) {
}
window.zoomToAndShowPortal = function(guid, latlng) {
renderPortalDetails(guid);
map.setView(latlng, 17);
// if the data is available, render it immediately. Otherwise defer
// until it becomes available.
if(window.portals[guid])
renderPortalDetails(guid);
else
urlPortal = guid;
}
// translates guids to entity types
@ -147,6 +159,8 @@ window.getTypeByGuid = function(guid) {
// .b == fields
// .c == player/creator
// .d == chat messages
//
// resonator guid is [portal guid]-resonator-[slot]
switch(guid.slice(33)) {
case '11':
case '12':
@ -165,6 +179,7 @@ window.getTypeByGuid = function(guid) {
return TYPE_CHAT;
default:
if(guid.slice(-11,-2) == 'resonator') return TYPE_RESONATOR;
return TYPE_UNKNOWN;
}
}
@ -183,3 +198,11 @@ if (typeof String.prototype.startsWith !== 'function') {
window.prettyEnergy = function(nrg) {
return nrg> 1000 ? Math.round(nrg/1000) + 'k': nrg;
}
window.setPermaLink = function(elm) {
var c = map.getCenter();
var lat = Math.round(c.lat*1E6);
var lng = Math.round(c.lng*1E6);
var qry = 'latE6='+lat+'&lngE6='+lng+'&z=' + map.getZoom();
$(elm).attr('href', 'http://www.ingress.com/intel?' + qry);
}