Merge branch 'master' into release

This commit is contained in:
Jon Atkins 2013-11-11 23:43:19 +00:00
commit 3b2c2d17e9
52 changed files with 2330 additions and 838 deletions

254
code/artifact.js Normal file
View File

@ -0,0 +1,254 @@
// ARTIFACT ///////////////////////////////////////////////////////
// added as part of the ingress #13magnus in november 2013, artifacts
// are additional game elements overlayed on the intel map
// currently there are only jarvis-related entities
// - shards: move between portals (along links) each hour. more than one can be at a portal
// - targets: specific portals - one per team
// the artifact data includes details for the specific portals, so can be useful
window.artifact = function() {}
window.artifact.setup = function() {
artifact.REFRESH_SUCCESS = 15*60; // 15 minutes on success
artifact.REFRESH_FAILURE = 2*60; // 2 minute retry on failure
artifact.idle = false;
artifact.clearData();
addResumeFunction(artifact.idleResume);
artifact.requestData();
artifact._layer = new L.LayerGroup();
addLayerGroup ('Artifacts (Jarvis shards)', artifact._layer, true);
$('#toolbox').append(' <a onclick="window.artifact.showArtifactList()" title="Show artifact portal list (jarvis shards and targets)">Artifacts</a>');
}
window.artifact.requestData = function() {
if (isIdle()) {
artifact.idle = true;
} else {
window.postAjax('getArtifactInfo', {}, artifact.handleSuccess, artifact.handleError);
}
}
window.artifact.idleResume = function() {
if (artifact.idle) {
artifact.idle = false;
artifact.requestData();
}
}
window.artifact.handleSuccess = function(data) {
artifact.processData (data);
setTimeout (artifact.requestData, artifact.REFRESH_SUCCESS*1000);
}
window.artifact.handleFailure = function(data) {
// no useful data on failure - do nothing
setTimeout (artifact.requestData, artifact.REFRESH_FAILURE*1000);
}
window.artifact.processData = function(data) {
if (!data.artifacts) {
console.warn('Failed to find artifacts in artifact response');
return;
}
artifact.clearData();
$.each (data.artifacts, function(i,artData) {
if (artData.artifactId != 'jarvis') {
// jarvis artifacts - fragmentInfos and targetInfos
// (future types? completely unknown at this time!)
console.warn('Note: unknown artifactId '+artData.artifactId+' - guessing how to handle it');
}
artifact.artifactTypes[artData.artifactId] = artData.artifactId;
if (artData.fragmentInfos) {
artifact.processFragmentInfos (artData.artifactId, artData.fragmentInfos);
}
if (artData.targetInfos) {
artifact.processTargetInfos (artData.artifactId, artData.targetInfos);
}
// other data in future? completely unknown!
});
// redraw the artifact layer
artifact.updateLayer();
}
window.artifact.clearData = function() {
artifact.portalInfo = {};
artifact.artifactTypes = {};
}
window.artifact.processFragmentInfos = function (id, fragments) {
$.each(fragments, function(i, fragment) {
if (!artifact.portalInfo[fragment.portalGuid]) {
artifact.portalInfo[fragment.portalGuid] = { _entityData: fragment.portalInfo };
}
if (!artifact.portalInfo[fragment.portalGuid][id]) artifact.portalInfo[fragment.portalGuid][id] = {};
if (!artifact.portalInfo[fragment.portalGuid][id].fragments) artifact.portalInfo[fragment.portalGuid][id].fragments = [];
$.each(fragment.fragments, function(i,f) {
artifact.portalInfo[fragment.portalGuid][id].fragments.push(f);
});
});
}
window.artifact.processTargetInfos = function (id, targets) {
$.each(targets, function(i, target) {
if (!artifact.portalInfo[target.portalGuid]) {
artifact.portalInfo[target.portalGuid] = { _entityData: target.portalInfo };
}
if (!artifact.portalInfo[target.portalGuid][id]) artifact.portalInfo[target.portalGuid][id] = {};
artifact.portalInfo[target.portalGuid][id].target = target.team === 'RESISTANCE' ? TEAM_RES : TEAM_ENL;
});
}
window.artifact.getArtifactTypes = function() {
return Object.keys(artifact.artifactTypes);
}
window.artifact.isArtifact = function(type) {
return type in artifact.artifactTypes;
}
// used to render portals that would otherwise be below the visible level
window.artifact.getArtifactEntities = function() {
var entities = [];
// create fake entities from the artifact data
$.each (artifact.portalInfo, function(guid,data) {
var timestamp = 0; // we don't have a valid timestamp - so let's use 0
var ent = [ guid, timestamp, data._entityData ];
entities.push(ent);
});
return entities;
}
window.artifact.getInterestingPortals = function() {
return Object.keys(artifact.portalInfo);
}
// quick test for portal being relevant to artifacts - of any type
window.artifact.isInterestingPortal = function(guid) {
return guid in artifact.portalInfo;
}
// get the artifact data for a specified artifact id (e.g. 'jarvis'), if it exists - otherwise returns something 'false'y
window.artifact.getPortalData = function(guid,artifactId) {
return artifact.portalInfo[guid] && artifact.portalInfo[guid][artifactId];
}
window.artifact.updateLayer = function() {
artifact._layer.clearLayers();
$.each(artifact.portalInfo, function(guid,data) {
var latlng = L.latLng ([data._entityData.locationE6.latE6/1E6, data._entityData.locationE6.lngE6/1E6]);
// jarvis shard icon
var iconUrl = undefined;
var iconSize = 0;
if (data.jarvis.fragments) {
iconUrl = '//commondatastorage.googleapis.com/ingress.com/img/map_icons/marker_images/jarvis_shard.png';
iconSize = 60/2; // 60 pixels - half that size works better
}
if (data.jarvis.target) {
// target portal - show the target marker. use the count of fragments at the target to pick the right icon - it has segments that fill up
var count = data.jarvis.fragments ? data.jarvis.fragments.length : 0;
iconUrl = '//commondatastorage.googleapis.com/ingress.com/img/map_icons/marker_images/jarvis_shard_target_'+count+'.png';
iconSize = 100/2; // 100 pixels - half that size works better
}
if (iconUrl) {
var icon = L.icon({
iconUrl: iconUrl,
iconSize: [iconSize,iconSize],
iconAnchor: [iconSize/2,iconSize/2],
className: 'no-pointer-events' // the clickable: false below still blocks events going through to the svg underneath
});
var marker = L.marker (latlng, {icon: icon, clickable: false, keyboard: false});
artifact._layer.addLayer(marker);
} else {
console.warn('Oops! no URL for artifact portal icon?!');
}
});
}
window.artifact.showArtifactList = function() {
var html = '<div><b>Artifact portals</b></div>';
var types = { 'jarvis': 'Jarvis Shards' };
$.each(types, function(type, name) {
html += '<hr><div><b>'+types[type]+'</b></div>';
html += '<table><tr><th>Portal</th><th>Details</th></tr>';
$.each(artifact.portalInfo, function(guid, data) {
if (type in data) {
// this portal has data for this artifact type - add it to the table
var onclick = 'zoomToAndShowPortal(\''+guid+'\',['+data._entityData.locationE6.latE6/1E6+','+data._entityData.locationE6.lngE6/1E6+'])';
html += '<tr><td><a onclick="'+onclick+'" title="'+escapeHtmlSpecialChars(data._entityData.portalV2.descriptiveText.ADDRESS||'')+'">'+escapeHtmlSpecialChars(data._entityData.portalV2.descriptiveText.TITLE)+'</a></td>';
html += '<td>';
if (data[type].target) {
html += '<span class="'+TEAM_TO_CSS[data[type].target]+'">'+(data[type].target==TEAM_RES?'Resistance':'Enlightened')+' target</span> ';
}
if (data[type].fragments) {
html += '<span class="fragments">Shard: #'+data[type].fragments.join(', #')+'</span> ';
}
html += '</td></tr>';
}
});
html += '</table>';
});
dialog({
title: 'Artifacts',
html: html,
width: 400,
position: {my: 'right center', at: 'center-60 center', of: window, collision: 'fit'}
});
}

View File

@ -525,6 +525,7 @@ function boot() {
window.setupLargeImagePreview();
window.setupSidebarToggle();
window.updateGameScore();
window.artifact.setup();
window.setupPlayerStat();
window.setupTooltips();
window.chat.setup();

View File

@ -33,7 +33,8 @@ window.Render.prototype.clearPortalsBelowLevel = function(level) {
var count = 0;
for (var guid in window.portals) {
var p = portals[guid];
if (parseInt(p.options.level) < level && guid !== selectedPortal) {
// clear portals below specified level - unless it's the selected portal, or it's relevant to artifacts
if (parseInt(p.options.level) < level && guid !== selectedPortal && !artifact.isInterestingPortal(guid)) {
this.deletePortalEntity(guid);
count++;
}
@ -46,7 +47,7 @@ window.Render.prototype.clearEntitiesOutsideBounds = function(bounds) {
for (var guid in window.portals) {
var p = portals[guid];
if (!bounds.contains (p.getLatLng()) && guid !== selectedPortal) {
if (!bounds.contains (p.getLatLng()) && guid !== selectedPortal && !artifact.isInterestingPortal(guid)) {
this.deletePortalEntity(guid);
pcount++;
}
@ -128,6 +129,7 @@ window.Render.prototype.endRenderPass = function() {
// check to see if there's eny entities we haven't seen. if so, delete them
for (var guid in window.portals) {
// special case for selected portal - it's kept even if not seen
if (!(guid in this.seenPortalsGuid) && guid !== selectedPortal) {
this.deletePortalEntity(guid);
}
@ -153,25 +155,32 @@ window.Render.prototype.bringPortalsToFront = function() {
for (var lvl in portalsFactionLayers) {
// portals are stored in separate layers per faction
// to avoid giving weight to one faction or another, we'll push portals to front based on GUID order
var portals = {};
var lvlPortals = {};
for (var fac in portalsFactionLayers[lvl]) {
var layer = portalsFactionLayers[lvl][fac];
if (layer._map) {
layer.eachLayer (function(p) {
portals[p.options.guid] = p;
lvlPortals[p.options.guid] = p;
});
}
}
var guids = Object.keys(portals);
var guids = Object.keys(lvlPortals);
guids.sort();
for (var j in guids) {
var guid = guids[j];
portals[guid].bringToFront();
lvlPortals[guid].bringToFront();
}
}
// artifact portals are always brought to the front, above all others
$.each(artifact.getInterestingPortals(), function(i,guid) {
if (portals[guid] && portals[guid]._map) {
portals[guid].bringToFront();
}
});
}
@ -544,7 +553,7 @@ window.Render.prototype.resetPortalClusters = function() {
var guid = c[i];
var p = window.portals[guid];
var layerGroup = portalsFactionLayers[parseInt(p.options.level)][p.options.team];
if (i<this.CLUSTER_PORTAL_LIMIT || p.options.guid == selectedPortal) {
if (i<this.CLUSTER_PORTAL_LIMIT || p.options.guid == selectedPortal || artifact.isInterestingPortal(p.options.guid)) {
if (!layerGroup.hasLayer(p)) {
layerGroup.addLayer(p);
}
@ -570,7 +579,7 @@ window.Render.prototype.addPortalToMapLayer = function(portal) {
// now, at this point, we could match the above re-clustr code - sorting, and adding/removing as necessary
// however, it won't make a lot of visible difference compared to just pushing to the end of the list, then
// adding to the visible layer if the list is below the limit
if (this.portalClusters[cid].length < this.CLUSTER_PORTAL_LIMIT || portal.options.guid == selectedPortal) {
if (this.portalClusters[cid].length < this.CLUSTER_PORTAL_LIMIT || portal.options.guid == selectedPortal || artifact.isInterestingPortal(portal.options.guid)) {
portalsFactionLayers[parseInt(portal.options.level)][portal.options.team].addLayer(portal);
}
}

View File

@ -213,6 +213,7 @@ window.MapDataRequest.prototype.refresh = function() {
this.render.updateEntityVisibility();
this.render.processGameEntities(artifact.getArtifactEntities());
console.log('requesting data tiles at zoom '+zoom+' (L'+minPortalLevel+'+ portals), map zoom is '+map.getZoom());

264
code/munge.js Normal file
View File

@ -0,0 +1,264 @@
// REQUEST PARAMETER MUNGING /////////////////////////////////////////////
//TODO: the double inclusion is planned - but not yet in place
// WARNING: this code is included in IITC twice!
// once within the main body of IITC code, inside the wrapper function
// additionally, outside of the wrapper code - used to detect if the required munging code will work
// before IITC actually starts
window.requestParameterMunges = [
// now obsolete (they don't have some of the new parameters) munge sets deleted
// set 6 - 2013-10-29
{
'dashboard.getGameScore': 'vzjhib746rvkre04', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': 'gqa96zhqpddtfmkl', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '18lmw7lytgxji0dk', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'emb5xrj8rav1i0be', // LOOKUP_PLAYERS
'dashboard.redeemReward': '4xqof5pldqab63rb', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'yq5wxjlnud0tj6hu', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'e1ipqdxjlwd3l7zb', // SEND_PLEXT
// common parameters
method: 'wg7gyxoanqc1si5r',
version: 'adlo9o4kjvho5q94', //guessed parameter name - only seen munged
version_parameter: '56036a6497ea344a9fffa38b171a77c092c1f220', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: '6vcl0ivqz4aj5sfu', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: '6jd5b49wn748diye',
minLatE6: '891ebsryg45b8cxb',
minLngE6: 'mvepdcx1k6noya15',
maxLatE6: 's3rh3fhji5mcjlof',
maxLngE6: 'yqdgfuukrxj8byzj',
minTimestampMs: 'btf0kpztxrkt6sl6',
maxTimestampMs: 'hg8vhtehxf53n5cu',
chatTab: '6bk9rmebtk1ux6da', //guessed parameter name - only seen munged
ascendingTimestampOrder: '4zw3v6xwp117r47w',
// SEND_PLEXT
message: '55vpsci0hji0ai5x',
latE6: 'lyhrt4miuwc7w29d',
lngE6: 'c1yl2qmzfu5j23ao',
// chatTab: '6bk9rmebtk1ux6da', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: 'k76phw8ey9z21z7c',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'x16pe9u4i8bidbi2',
},
// set 7 - 2013-11-06
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfsucated?!)
'dashboard.getGameScore': 'yol4dxx5ufqolhk2', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': '7b83j2z81rtk6101', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '46su4lrisoq28gxh', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'wsc5puahrymtf1qh', // LOOKUP_PLAYERS
'dashboard.redeemReward': 'oo0n7pw2m0xufpzx', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'bo1bp74rz8kbdjkb', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'q0f8o4v9t8pt91yv', // SEND_PLEXT
// common parameters
method: 'imo60cdzkemxduub',
version: '54lh4o0q7nz7dao9', //guessed parameter name - only seen munged
version_parameter: '370c0b4e160ed26c8c4ce40f10f546545730e1ef', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: 'iqy8e2d3zpne0cmh', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: 'chwe3yko3xy0qlk3',
minLatE6: 'f31z3x27ua8i05cf',
minLngE6: 't0rmob7f42c0w04r',
maxLatE6: 'ebwfvri5io9q0tvu',
maxLngE6: 'lfqzvpj92dp8uxo6',
minTimestampMs: '23a6djyyieeaeduu',
maxTimestampMs: 'zhjtsm2gw7w3b7mx',
chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'v5rzzxtg5rmry3dx',
// SEND_PLEXT
message: 'onptntn3szan21lj',
latE6: '1jq9lgu3hjajrt7s',
lngE6: 'plbubiopnavbxxh6',
// chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '919p2cfpdo2wz03n',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'thpbnoyjx0antwm5',
},
// set 8 - 2013-11-07
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfsucated?!)
'dashboard.getGameScore': 'lls4clhel87apzpa', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': 'r6n2xgcd8wjsm4og', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '1ybigzcf2sifu34b', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'uig0xeb6trclqd2l', // LOOKUP_PLAYERS
'dashboard.redeemReward': '7dd7x64cc2lbutoq', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'd8p6dvwilsr460u3', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'repg2orpg7htkoto', // SEND_PLEXT
// common parameters
method: '97aes4vnlvyhoxik',
version: 'an8mglz21qabq3wq', //guessed parameter name - only seen munged
version_parameter: 'b92c9d055fcdf715887b173c706e7a2c267e32c5', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: 'mhjknavysslwfhk6', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: 'l61g8u397alq3j1x',
minLatE6: 'wwsvpboc5bxd1s9q',
minLngE6: '48l4x7ngfsz47z3u',
maxLatE6: 'p3m1qg81uqldizu6',
maxLngE6: 'h4kv1eef878vfyk3',
minTimestampMs: 'uj1vcy9ufws24v2c',
maxTimestampMs: '8pt1x5nd9hk5vakv',
chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'duyuskmky68nl2ci',
// SEND_PLEXT
message: 'xktwjguq0nohzioa',
latE6: 'm4crflfaibmg9mdf',
lngE6: 'h6jfungrw5ii830r',
// chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '3u9h9cpfh2yiy4fk',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'jpg3y4ax7t0w356j',
},
// set 9 - 2013-11-1
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfsucated?!)
'dashboard.getGameScore': '9w8phj2dccvns3t9', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': '3b1nc3ub0sd1704x', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '2xa55qj41qrhfhas', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': '734hxjh89d53clqq', // LOOKUP_PLAYERS
'dashboard.redeemReward': 'k3hwg41wf112gjjh', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'uwizjeb18xmcesa0', // SEND_INVITE_EMAIL
'dashboard.sendPlext': '5au1m1hut1gyvnix', // SEND_PLEXT
// common parameters
method: '3sld77nsm0tjmkvi',
version: 'xz7q6r3aja5ttvoo', //guessed parameter name - only seen munged
version_parameter: 'b121024077de2a0dc6b34119e4440785c9ea5e64', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: '0o6bkrbwevwn6bg1', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: '3fketl1tv01q7vxu',
minLatE6: '5i6jhgbv3aq3c4qz',
minLngE6: 'pe2io3r932qysg4u',
maxLatE6: 'plzyuy89bnlb3pth',
maxLngE6: 'q0qq1ooc7sxpynth',
minTimestampMs: 'nc282s8hdklv21mw',
maxTimestampMs: 'ezrljj0l71gpelpu',
chatTab: 'efaznrayv5n3jxs0', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'fcmlcb8ya0oa1clk',
// SEND_PLEXT
message: 'jg4ms2i14rgzi02n',
latE6: 'nkf3evzpkxkq8l2q',
lngE6: '7xoz0xl8se4d1j53',
// chatTab: 'efaznrayv5n3jxs0', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: 'm4dcrdltldigfo94',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'rye9be4um2t1z5ts',
},
];
window.activeRequestMungeSet = undefined;
// attempt to guess the munge set in use, by looking therough the functions of the stock intel page for one of the munged params
window.detectActiveMungeSet = function() {
// try and find the stock page functions
// FIXME? revert to searching through all the code? is that practical?
var stockFunc;
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.doSendRequest_.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.sendRequest.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.DataFetcher.prototype.sendRequest_.toString();
} catch(e) {
console.warn('Failed to find a relevant function in the stock site');
}
}
}
if(stockFunc) {
for (var i in window.requestParameterMunges) {
if (stockFunc.indexOf (window.requestParameterMunges[i]['method']) >= 0) {
console.log('IITC: found request munge set index '+i+' in stock intel site');
window.activeRequestMungeSet = i;
}
}
} else {
console.error('IITC: failed to find the stock site function for detecting munge set');
}
if (window.activeRequestMungeSet===undefined) {
console.error('IITC: failed to find request munge set - IITC will likely fail');
window.activeRequestMungeSet = 0;
}
}
// niantic now add some munging to the request parameters. so far, only two sets of this munging have been seen
window.requestDataMunge = function(data) {
var activeMunge = window.requestParameterMunges[window.activeRequestMungeSet];
function munge(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
// an array - munge each element of it
var newobj = [];
for (var i in obj) {
newobj[i] = munge(obj[i]);
}
return newobj;
} else if (typeof obj === 'object') {
// an object: munge each property name, and pass the value through the munge process
var newobj = Object();
for (var p in obj) {
var m = activeMunge[p];
if (m === undefined) {
console.error('Error: failed to find munge for object property '+p);
newobj[p] = obj[p];
} else {
// rename the property
newobj[m] = munge(obj[p]);
}
}
return newobj;
} else {
// neither an array or an object - so must be a simple value. return it unmodified
return obj;
}
};
var newdata = munge(data);
return newdata;
}

View File

@ -31,7 +31,8 @@ window.renderPortalDetails = function(guid) {
var playerText = player ? ['owner', player] : null;
var time = d.captured
? '<span title="' + unixTimeToDateTimeString(d.captured.capturedTime, false) + '">'
? '<span title="' + unixTimeToDateTimeString(d.captured.capturedTime, false) + '\n'
+ formatInterval(Math.floor((Date.now()-d.captured.capturedTime)/1000), 2) + ' ago">'
+ unixTimeToString(d.captured.capturedTime) + '</span>'
: null;
var sinceText = time ? ['since', time] : null;
@ -46,6 +47,26 @@ window.renderPortalDetails = function(guid) {
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', '<span class="'+TEAM_TO_CSS[jarvisArtifact.target]+'">'+(jarvisArtifact.target==TEAM_RES?'Resistance':'Enlightened')+'</span>'];
}
if (jarvisArtifact.fragments) {
shards = [jarvisArtifact.fragments.length>1?'shards':'shard', '#'+jarvisArtifact.fragments.join(', #')];
}
randDetails.push (target, shards);
}
randDetails = '<table id="randdetails">' + genFourColumnTable(randDetails) + '</table>';
var resoDetails = '<table id="resodetails">' + getResonatorDetails(d) + '</table>';

View File

@ -2,8 +2,8 @@
window.aboutIITC = function() {
var v = (script_info.script && script_info.script.version || script_info.dateTimeVersion) + ' ['+script_info.buildName+']';
if (typeof android !== 'undefined' && android && android.getVersionCode) {
v += '[IITC Mobile '+android.getVersionCode()+']';
if (typeof android !== 'undefined' && android && android.getVersionName) {
v += '[IITC Mobile '+android.getVersionName()+']';
}
var plugins = '<ul>';
@ -126,212 +126,6 @@ window.digits = function(d) {
}
window.requestParameterMunges = [
// now obsolete (they don't have some of the new parameters) munge sets deleted
// set 6 - 2013-10-29
{
'dashboard.getGameScore': 'vzjhib746rvkre04', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': 'gqa96zhqpddtfmkl', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '18lmw7lytgxji0dk', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'emb5xrj8rav1i0be', // LOOKUP_PLAYERS
'dashboard.redeemReward': '4xqof5pldqab63rb', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'yq5wxjlnud0tj6hu', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'e1ipqdxjlwd3l7zb', // SEND_PLEXT
// common parameters
method: 'wg7gyxoanqc1si5r',
version: 'adlo9o4kjvho5q94', //guessed parameter name - only seen munged
version_parameter: '56036a6497ea344a9fffa38b171a77c092c1f220', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: '6vcl0ivqz4aj5sfu', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: '6jd5b49wn748diye',
minLatE6: '891ebsryg45b8cxb',
minLngE6: 'mvepdcx1k6noya15',
maxLatE6: 's3rh3fhji5mcjlof',
maxLngE6: 'yqdgfuukrxj8byzj',
minTimestampMs: 'btf0kpztxrkt6sl6',
maxTimestampMs: 'hg8vhtehxf53n5cu',
chatTab: '6bk9rmebtk1ux6da', //guessed parameter name - only seen munged
ascendingTimestampOrder: '4zw3v6xwp117r47w',
// SEND_PLEXT
message: '55vpsci0hji0ai5x',
latE6: 'lyhrt4miuwc7w29d',
lngE6: 'c1yl2qmzfu5j23ao',
// chatTab: '6bk9rmebtk1ux6da', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: 'k76phw8ey9z21z7c',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'x16pe9u4i8bidbi2',
},
// set 7 - 2013-11-06
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfsucated?!)
'dashboard.getGameScore': 'yol4dxx5ufqolhk2', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': '7b83j2z81rtk6101', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '46su4lrisoq28gxh', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'wsc5puahrymtf1qh', // LOOKUP_PLAYERS
'dashboard.redeemReward': 'oo0n7pw2m0xufpzx', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'bo1bp74rz8kbdjkb', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'q0f8o4v9t8pt91yv', // SEND_PLEXT
// common parameters
method: 'imo60cdzkemxduub',
version: '54lh4o0q7nz7dao9', //guessed parameter name - only seen munged
version_parameter: '370c0b4e160ed26c8c4ce40f10f546545730e1ef', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: 'iqy8e2d3zpne0cmh', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: 'chwe3yko3xy0qlk3',
minLatE6: 'f31z3x27ua8i05cf',
minLngE6: 't0rmob7f42c0w04r',
maxLatE6: 'ebwfvri5io9q0tvu',
maxLngE6: 'lfqzvpj92dp8uxo6',
minTimestampMs: '23a6djyyieeaeduu',
maxTimestampMs: 'zhjtsm2gw7w3b7mx',
chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'v5rzzxtg5rmry3dx',
// SEND_PLEXT
message: 'onptntn3szan21lj',
latE6: '1jq9lgu3hjajrt7s',
lngE6: 'plbubiopnavbxxh6',
// chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '919p2cfpdo2wz03n',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'thpbnoyjx0antwm5',
},
// set 8 - 2013-11-07
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfsucated?!)
'dashboard.getGameScore': 'lls4clhel87apzpa', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': 'r6n2xgcd8wjsm4og', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '1ybigzcf2sifu34b', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'uig0xeb6trclqd2l', // LOOKUP_PLAYERS
'dashboard.redeemReward': '7dd7x64cc2lbutoq', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'd8p6dvwilsr460u3', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'repg2orpg7htkoto', // SEND_PLEXT
// common parameters
method: '97aes4vnlvyhoxik',
version: 'an8mglz21qabq3wq', //guessed parameter name - only seen munged
version_parameter: 'b92c9d055fcdf715887b173c706e7a2c267e32c5', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: 'mhjknavysslwfhk6', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: 'l61g8u397alq3j1x',
minLatE6: 'wwsvpboc5bxd1s9q',
minLngE6: '48l4x7ngfsz47z3u',
maxLatE6: 'p3m1qg81uqldizu6',
maxLngE6: 'h4kv1eef878vfyk3',
minTimestampMs: 'uj1vcy9ufws24v2c',
maxTimestampMs: '8pt1x5nd9hk5vakv',
chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'duyuskmky68nl2ci',
// SEND_PLEXT
message: 'xktwjguq0nohzioa',
latE6: 'm4crflfaibmg9mdf',
lngE6: 'h6jfungrw5ii830r',
// chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '3u9h9cpfh2yiy4fk',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'jpg3y4ax7t0w356j',
},
];
window.activeRequestMungeSet = undefined;
// attempt to guess the munge set in use, by looking therough the functions of the stock intel page for one of the munged params
window.detectActiveMungeSet = function() {
// try and find the stock page functions
// FIXME? revert to searching through all the code? is that practical?
var stockFunc;
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.doSendRequest_.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.sendRequest.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.DataFetcher.prototype.sendRequest_.toString();
} catch(e) {
console.warn('Failed to find a relevant function in the stock site');
}
}
}
if(stockFunc) {
for (var i in window.requestParameterMunges) {
if (stockFunc.indexOf (window.requestParameterMunges[i]['method']) >= 0) {
console.log('IITC: found request munge set index '+i+' in stock intel site');
window.activeRequestMungeSet = i;
}
}
} else {
console.error('IITC: failed to find the stock site function for detecting munge set');
}
if (window.activeRequestMungeSet===undefined) {
console.error('IITC: failed to find request munge set - IITC will likely fail');
window.activeRequestMungeSet = 0;
}
}
// niantic now add some munging to the request parameters. so far, only two sets of this munging have been seen
window.requestDataMunge = function(data) {
var activeMunge = window.requestParameterMunges[window.activeRequestMungeSet];
function munge(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
// an array - munge each element of it
var newobj = [];
for (var i in obj) {
newobj[i] = munge(obj[i]);
}
return newobj;
} else if (typeof obj === 'object') {
// an object: munge each property name, and pass the value through the munge process
var newobj = Object();
for (var p in obj) {
var m = activeMunge[p];
if (m === undefined) {
console.error('Error: failed to find munge for object property '+p);
newobj[p] = obj[p];
} else {
// rename the property
newobj[m] = munge(obj[p]);
}
}
return newobj;
} else {
// neither an array or an object - so must be a simple value. return it unmodified
return obj;
}
};
var newdata = munge(data);
return newdata;
}
// posts AJAX request to Ingress API.
// action: last part of the actual URL, the rpc/dashboard. is
@ -414,18 +208,22 @@ window.unixTimeToHHmm = function(time) {
return h + ':' + s;
}
window.formatInterval = function(seconds) {
window.formatInterval = function(seconds,maxTerms) {
var h = Math.floor(seconds / 3600);
var d = Math.floor(seconds / 86400);
var h = Math.floor((seconds % 86400) / 3600);
var m = Math.floor((seconds % 3600) / 60);
var s = seconds % 60;
var text = '';
if (h > 0) text += h+'h';
if (m > 0) text += m+'m';
if (s > 0 || text == '') text += s+'s';
var terms = [];
if (d > 0) terms.push(d+'d');
if (h > 0) terms.push(h+'h');
if (m > 0) terms.push(m+'m');
if (s > 0 || terms.length==0) terms.push(s+'s');
return text;
if (maxTerms) terms = terms.slice(0,maxTerms);
return terms.join(' ');
}
@ -459,6 +257,11 @@ window.showPortalPosLinks = function(lat, lng, name) {
}
}
window.isTouchDevice = function() {
return 'ontouchstart' in window // works on most browsers
|| 'onmsgesturechange' in window; // works on ie10
};
window.androidCopy = function(text) {
if(typeof android === 'undefined' || !android || !android.copy)
return true; // i.e. execute other actions

File diff suppressed because it is too large Load Diff

65
external/leaflet.css vendored
View File

@ -42,6 +42,10 @@
.leaflet-container img.leaflet-image-layer {
max-width: 15000px !important;
}
/* Android chrome makes tiles disappear without this */
.leaflet-tile-container img {
-webkit-backface-visibility: hidden;
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
@ -65,6 +69,16 @@
.leaflet-marker-pane { z-index: 6; }
.leaflet-popup-pane { z-index: 7; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
@ -182,9 +196,8 @@
outline: 2px solid orange;
}
.leaflet-zoom-box {
border: 2px dotted #05f;
background: white;
opacity: 0.5;
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
@ -201,7 +214,8 @@
-webkit-border-radius: 4px;
border-radius: 4px;
}
.leaflet-bar a, .leaflet-bar a:hover {
.leaflet-bar a,
.leaflet-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
@ -286,7 +300,7 @@
.leaflet-control-layers {
box-shadow: 0 1px 7px rgba(0,0,0,0.4);
background: #f8f8f9;
background: #fff;
-webkit-border-radius: 5px;
border-radius: 5px;
}
@ -296,7 +310,7 @@
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(@@INCLUDEIMAGE:images/layers-2x.png@@);
background-image: url(@@INCLUDEIMATE:images/layers-2x.png@@);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
@ -334,7 +348,8 @@
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background-color: rgba(255, 255, 255, 0.7);
background: #fff;
background: rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px #bbb;
margin: 0;
}
@ -356,15 +371,19 @@
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
color: black;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
text-shadow: 1px 1px 1px #fff;
background-color: rgba(255, 255, 255, 0.5);
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: content-box;
box-sizing: content-box;
color: black;
background: #fff;
background: rgba(255, 255, 255, 0.5);
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
text-shadow: 1px 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
@ -426,7 +445,8 @@
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
@ -454,6 +474,27 @@
border-top: 1px solid #ddd;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-popup-tip-container {
margin-top: -1px;
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */

8
external/leaflet.js vendored

File diff suppressed because one or more lines are too long

22
external/oms.min.js vendored
View File

@ -5,15 +5,15 @@ Copyright (c) 2011 - 2012 George MacKerron
Released under the MIT licence: http://opensource.org/licenses/mit-license
Note: The Leaflet maps API must be included *before* this code
*/
(function(){var n={}.hasOwnProperty,o=[].slice;null!=this.L&&(this.OverlappingMarkerSpiderfier=function(){function l(c,b){var a,e,g,f,d=this;this.map=c;null==b&&(b={});for(a in b)n.call(b,a)&&(e=b[a],this[a]=e);this.initMarkerArrays();this.listeners={};f=["click","zoomend"];e=0;for(g=f.length;e<g;e++)a=f[e],this.map.addEventListener(a,function(){return d.unspiderfy()})}var d,i;d=l.prototype;d.VERSION="0.2.5";i=2*Math.PI;d.keepSpiderfied=!1;d.nearbyDistance=20;d.circleSpiralSwitchover=9;d.circleFootSeparation=
25;d.circleStartAngle=i/12;d.spiralFootSeparation=28;d.spiralLengthStart=11;d.spiralLengthFactor=5;d.legWeight=1.5;d.legColors={usual:"#222",highlighted:"#f00"};d.initMarkerArrays=function(){this.markers=[];return this.markerListeners=[]};d.addMarker=function(c){var b,a=this;if(null!=c._oms)return this;c._oms=!0;b=function(){return a.spiderListener(c)};c.addEventListener("click",b);this.markerListeners.push(b);this.markers.push(c);return this};d.getMarkers=function(){return this.markers.slice(0)};
(function(){var q={}.hasOwnProperty,r=[].slice;null!=this.L&&(this.OverlappingMarkerSpiderfier=function(){function n(c,b){var a,e,g,f,d=this;this.map=c;null==b&&(b={});for(a in b)q.call(b,a)&&(e=b[a],this[a]=e);this.initMarkerArrays();this.listeners={};f=["click","zoomend"];e=0;for(g=f.length;e<g;e++)a=f[e],this.map.addEventListener(a,function(){return d.unspiderfy()})}var d,k;d=n.prototype;d.VERSION="0.2.6";k=2*Math.PI;d.keepSpiderfied=!1;d.nearbyDistance=20;d.circleSpiralSwitchover=9;d.circleFootSeparation=
25;d.circleStartAngle=k/12;d.spiralFootSeparation=28;d.spiralLengthStart=11;d.spiralLengthFactor=5;d.legWeight=1.5;d.legColors={usual:"#222",highlighted:"#f00"};d.initMarkerArrays=function(){this.markers=[];return this.markerListeners=[]};d.addMarker=function(c){var b,a=this;if(null!=c._oms)return this;c._oms=!0;b=function(){return a.spiderListener(c)};c.addEventListener("click",b);this.markerListeners.push(b);this.markers.push(c);return this};d.getMarkers=function(){return this.markers.slice(0)};
d.removeMarker=function(c){var b,a;null!=c._omsData&&this.unspiderfy();b=this.arrIndexOf(this.markers,c);if(0>b)return this;a=this.markerListeners.splice(b,1)[0];c.removeEventListener("click",a);delete c._oms;this.markers.splice(b,1);return this};d.clearMarkers=function(){var c,b,a,e,g;this.unspiderfy();g=this.markers;c=a=0;for(e=g.length;a<e;c=++a)b=g[c],c=this.markerListeners[c],b.removeEventListener("click",c),delete b._oms;this.initMarkerArrays();return this};d.addListener=function(c,b){var a,
e;(null!=(e=(a=this.listeners)[c])?e:a[c]=[]).push(b);return this};d.removeListener=function(c,b){var a;a=this.arrIndexOf(this.listeners[c],b);0>a||this.listeners[c].splice(a,1);return this};d.clearListeners=function(c){this.listeners[c]=[];return this};d.trigger=function(){var c,b,a,e,g,f;b=arguments[0];c=2<=arguments.length?o.call(arguments,1):[];b=null!=(a=this.listeners[b])?a:[];f=[];e=0;for(g=b.length;e<g;e++)a=b[e],f.push(a.apply(null,c));return f};d.generatePtsCircle=function(c,b){var a,e,
g,f,d;g=this.circleFootSeparation*(2+c)/i;e=i/c;d=[];for(a=f=0;0<=c?f<c:f>c;a=0<=c?++f:--f)a=this.circleStartAngle+a*e,d.push(new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)));return d};d.generatePtsSpiral=function(c,b){var a,e,g,f,d;g=this.spiralLengthStart;a=0;d=[];for(e=f=0;0<=c?f<c:f>c;e=0<=c?++f:--f)a+=this.spiralFootSeparation/g+5.0E-4*e,e=new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)),g+=i*this.spiralLengthFactor/a,d.push(e);return d};d.spiderListener=function(c){var b,a,e,g,f,d,h,i,j;b=
null!=c._omsData;(!b||!this.keepSpiderfied)&&this.unspiderfy();if(b)return this.trigger("click",c);g=[];f=[];d=this.nearbyDistance*this.nearbyDistance;e=this.map.latLngToLayerPoint(c.getLatLng());j=this.markers;h=0;for(i=j.length;h<i;h++)b=j[h],a=this.map.latLngToLayerPoint(b.getLatLng()),this.ptDistanceSq(a,e)<d?g.push({marker:b,markerPt:a}):f.push(b);return 1===g.length?this.trigger("click",c):this.spiderfy(g,f)};d.makeHighlightListeners=function(c){var b=this;return{highlight:function(){return c._omsData.leg.setStyle({color:b.legColors.highlighted})},
unhighlight:function(){return c._omsData.leg.setStyle({color:b.legColors.usual})}}};d.spiderfy=function(c,b){var a,e,g,d,m,h,i,j,l,k;this.spiderfying=!0;k=c.length;a=this.ptAverage(function(){var a,b,e;e=[];a=0;for(b=c.length;a<b;a++)i=c[a],e.push(i.markerPt);return e}());d=k>=this.circleSpiralSwitchover?this.generatePtsSpiral(k,a).reverse():this.generatePtsCircle(k,a);a=function(){var a,b,i,k=this;i=[];a=0;for(b=d.length;a<b;a++)g=d[a],e=this.map.layerPointToLatLng(g),l=this.minExtract(c,function(a){return k.ptDistanceSq(a.markerPt,
g)}),h=l.marker,m=new L.Polyline([h.getLatLng(),e],{color:this.legColors.usual,weight:this.legWeight,clickable:!1}),this.map.addLayer(m),h._omsData={usualPosition:h.getLatLng(),leg:m},this.legColors.highlighted!==this.legColors.usual&&(j=this.makeHighlightListeners(h),h._omsData.highlightListeners=j,h.addEventListener("mouseover",j.highlight),h.addEventListener("mouseout",j.unhighlight)),h.setLatLng(e),h.setZIndexOffset(1E6),i.push(h);return i}.call(this);delete this.spiderfying;this.spiderfied=!0;
return this.trigger("spiderfy",a,b)};d.unspiderfy=function(c){var b,a,e,d,f,i,h;null==c&&(c=null);if(null==this.spiderfied)return this;this.unspiderfying=!0;d=[];e=[];h=this.markers;f=0;for(i=h.length;f<i;f++)b=h[f],null!=b._omsData?(this.map.removeLayer(b._omsData.leg),b!==c&&b.setLatLng(b._omsData.usualPosition),b.setZIndexOffset(0),a=b._omsData.highlightListeners,null!=a&&(b.removeEventListener("mouseover",a.highlight),b.removeEventListener("mouseout",a.unhighlight)),delete b._omsData,d.push(b)):
e.push(b);delete this.unspiderfying;delete this.spiderfied;this.trigger("unspiderfy",d,e);return this};d.ptDistanceSq=function(c,b){var a,e;a=c.x-b.x;e=c.y-b.y;return a*a+e*e};d.ptAverage=function(c){var b,a,e,d,f;d=a=e=0;for(f=c.length;d<f;d++)b=c[d],a+=b.x,e+=b.y;c=c.length;return new L.Point(a/c,e/c)};d.minExtract=function(c,b){var a,d,g,f,i,h;g=i=0;for(h=c.length;i<h;g=++i)if(f=c[g],f=b(f),!("undefined"!==typeof a&&null!==a)||f<d)d=f,a=g;return c.splice(a,1)[0]};d.arrIndexOf=function(c,b){var a,
d,g,f;if(null!=c.indexOf)return c.indexOf(b);a=g=0;for(f=c.length;g<f;a=++g)if(d=c[a],d===b)return a;return-1};return l}())}).call(this);}).call(this);
/* Sun 6 May 2012 17:49:10 BST */
e;(null!=(e=(a=this.listeners)[c])?e:a[c]=[]).push(b);return this};d.removeListener=function(c,b){var a;a=this.arrIndexOf(this.listeners[c],b);0>a||this.listeners[c].splice(a,1);return this};d.clearListeners=function(c){this.listeners[c]=[];return this};d.trigger=function(){var c,b,a,e,g,f;b=arguments[0];c=2<=arguments.length?r.call(arguments,1):[];b=null!=(a=this.listeners[b])?a:[];f=[];e=0;for(g=b.length;e<g;e++)a=b[e],f.push(a.apply(null,c));return f};d.generatePtsCircle=function(c,b){var a,e,
g,f,d;g=this.circleFootSeparation*(2+c)/k;e=k/c;d=[];for(a=f=0;0<=c?f<c:f>c;a=0<=c?++f:--f)a=this.circleStartAngle+a*e,d.push(new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)));return d};d.generatePtsSpiral=function(c,b){var a,e,g,f,d;g=this.spiralLengthStart;a=0;d=[];for(e=f=0;0<=c?f<c:f>c;e=0<=c?++f:--f)a+=this.spiralFootSeparation/g+5E-4*e,e=new L.Point(b.x+g*Math.cos(a),b.y+g*Math.sin(a)),g+=k*this.spiralLengthFactor/a,d.push(e);return d};d.spiderListener=function(c){var b,a,e,g,f,d,h,k,l;(b=null!=
c._omsData)&&this.keepSpiderfied||this.unspiderfy();if(b)return this.trigger("click",c);g=[];f=[];d=this.nearbyDistance*this.nearbyDistance;e=this.map.latLngToLayerPoint(c.getLatLng());l=this.markers;h=0;for(k=l.length;h<k;h++)b=l[h],this.map.hasLayer(b)&&(a=this.map.latLngToLayerPoint(b.getLatLng()),this.ptDistanceSq(a,e)<d?g.push({marker:b,markerPt:a}):f.push(b));return 1===g.length?this.trigger("click",c):this.spiderfy(g,f)};d.makeHighlightListeners=function(c){var b=this;return{highlight:function(){return c._omsData.leg.setStyle({color:b.legColors.highlighted})},
unhighlight:function(){return c._omsData.leg.setStyle({color:b.legColors.usual})}}};d.spiderfy=function(c,b){var a,e,g,d,p,h,k,l,n,m;this.spiderfying=!0;m=c.length;a=this.ptAverage(function(){var a,b,e;e=[];a=0;for(b=c.length;a<b;a++)k=c[a],e.push(k.markerPt);return e}());d=m>=this.circleSpiralSwitchover?this.generatePtsSpiral(m,a).reverse():this.generatePtsCircle(m,a);a=function(){var a,b,k,m=this;k=[];a=0;for(b=d.length;a<b;a++)g=d[a],e=this.map.layerPointToLatLng(g),n=this.minExtract(c,function(a){return m.ptDistanceSq(a.markerPt,
g)}),h=n.marker,p=new L.Polyline([h.getLatLng(),e],{color:this.legColors.usual,weight:this.legWeight,clickable:!1}),this.map.addLayer(p),h._omsData={usualPosition:h.getLatLng(),leg:p},this.legColors.highlighted!==this.legColors.usual&&(l=this.makeHighlightListeners(h),h._omsData.highlightListeners=l,h.addEventListener("mouseover",l.highlight),h.addEventListener("mouseout",l.unhighlight)),h.setLatLng(e),h.setZIndexOffset(1E6),k.push(h);return k}.call(this);delete this.spiderfying;this.spiderfied=!0;
return this.trigger("spiderfy",a,b)};d.unspiderfy=function(c){var b,a,e,d,f,k,h;null==c&&(c=null);if(null==this.spiderfied)return this;this.unspiderfying=!0;d=[];e=[];h=this.markers;f=0;for(k=h.length;f<k;f++)b=h[f],null!=b._omsData?(this.map.removeLayer(b._omsData.leg),b!==c&&b.setLatLng(b._omsData.usualPosition),b.setZIndexOffset(0),a=b._omsData.highlightListeners,null!=a&&(b.removeEventListener("mouseover",a.highlight),b.removeEventListener("mouseout",a.unhighlight)),delete b._omsData,d.push(b)):
e.push(b);delete this.unspiderfying;delete this.spiderfied;this.trigger("unspiderfy",d,e);return this};d.ptDistanceSq=function(c,b){var a,e;a=c.x-b.x;e=c.y-b.y;return a*a+e*e};d.ptAverage=function(c){var b,a,e,d,f;d=a=e=0;for(f=c.length;d<f;d++)b=c[d],a+=b.x,e+=b.y;c=c.length;return new L.Point(a/c,e/c)};d.minExtract=function(c,b){var a,d,g,f,k,h;g=k=0;for(h=c.length;k<h;g=++k)if(f=c[g],f=b(f),"undefined"===typeof a||null===a||f<d)d=f,a=g;return c.splice(a,1)[0]};d.arrIndexOf=function(c,b){var a,
d,g,f;if(null!=c.indexOf)return c.indexOf(b);a=g=0;for(f=c.length;g<f;a=++g)if(d=c[a],d===b)return a;return-1};return n}())}).call(this);}).call(this);
/* Mon 14 Oct 2013 10:54:59 BST */

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @id ingress-intel-total-conversion@jonatkins
// @name IITC: Ingress intel map total conversion
// @version 0.14.6.@@DATETIMEVERSION@@
// @version 0.15.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@

18
mobile/.idea/misc.xml generated
View File

@ -10,24 +10,8 @@
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="Android 4.3 Platform" project-jdk-type="Android SDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="Android 4.4 Platform" project-jdk-type="Android SDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>Android 4.3 Platform</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@ -3,11 +3,11 @@
package="com.cradle.iitc_mobile"
android:installLocation="auto"
android:versionCode="59"
android:versionName="0.7.7.2">
android:versionName="0.9">
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="18"/>
android:targetSdkVersion="19"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@ -23,7 +23,7 @@
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="com.cradle.iitc_mobile.IITC_Mobile"
android:name=".IITC_Mobile"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
@ -89,11 +89,11 @@
android:name=".share.ShareActivity"
android:label="@string/activity_share"
android:noHistory="true"
android:parentActivityName="com.cradle.iitc_mobile.IITC_Mobile"
android:parentActivityName=".IITC_Mobile"
android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.cradle.iitc_mobile.IITC_Mobile"/>
android:value=".IITC_Mobile"/>
</activity>
<activity
@ -136,7 +136,7 @@
<!-- Points to searchable activity so the whole app can invoke search. -->
<meta-data
android:name="android.app.default_searchable"
android:value="com.cradle.iitc_mobile.IITC_Mobile"/>
android:value=".IITC_Mobile"/>
</application>
</manifest>

View File

@ -142,8 +142,8 @@
<replaceregexp
file="AndroidManifest.xml"
match='android:versionName="(\d+\.\d+\.\d+)"'
replace='android:versionName="\1.${git.version}"' />
match='android:versionName="(\d+(\.\d+)*)"'
replace='android:versionName="\1.${git.commits}.${git.version}"' />
</target>
<target name="-custom-restore-manifest">

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @id iitc-plugin-user-location@cradle
// @name IITC plugin: User Location
// @version 0.1.3.@@DATETIMEVERSION@@
// @version 0.1.4.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -35,10 +35,11 @@ window.plugin.userLocation.setup = function() {
var title = '<span class="nickname '+ cssClass+'" style="font-weight:bold;">' + PLAYER.nickname + '</span>\'s location';
var marker = L.marker(window.map.getCenter(), {
title: title,
icon: new plugin.userLocation.icon()
});
marker.bindPopup(title);
plugin.userLocation.marker = marker;
marker.addTo(window.map);
// jQueryUI doesnt automatically notice the new markers

View File

@ -11,4 +11,4 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-18
target=android-19

View File

@ -76,6 +76,19 @@ public class IITC_JSInterface {
return versionCode;
}
@JavascriptInterface
public String getVersionName() {
String buildVersion = "unknown";
PackageManager pm = mIitc.getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(mIitc.getPackageName(), 0);
buildVersion = info.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return buildVersion;
}
@JavascriptInterface
public void switchToPane(final String id) {
mIitc.runOnUiThread(new Runnable() {
@ -147,4 +160,14 @@ public class IITC_JSInterface {
}
});
}
@JavascriptInterface
public void updateIitc(final String fileUrl) {
mIitc.runOnUiThread(new Runnable() {
@Override
public void run() {
mIitc.updateIitc(fileUrl);
}
});
}
}

View File

@ -76,7 +76,7 @@ public class IITC_MapSettings implements OnItemSelectedListener, OnItemClickList
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Layer item = getItem(position);
View view = (TextView) super.getView(position, convertView, parent);
View view = super.getView(position, convertView, parent);
if (view instanceof CheckedTextView) {
((CheckedTextView) view).setChecked(item.active);

View File

@ -3,10 +3,13 @@ package com.cradle.iitc_mobile;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DownloadManager;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
@ -54,6 +57,13 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis
private IITC_NavigationHelper mNavigationHelper;
private IITC_MapSettings mMapSettings;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
((IITC_Mobile) context).installIitcUpdate();
}
};
// Used for custom back stack handling
private final Stack<Pane> mBackStack = new Stack<IITC_NavigationHelper.Pane>();
private boolean mBackStackPush = true;
@ -106,6 +116,10 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis
// Clear the back stack
mBackStack.clear();
// receive downloadManagers downloadComplete intent
// afterwards install iitc update
registerReceiver(mBroadcastReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
handleIntent(getIntent(), true);
}
@ -169,6 +183,7 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis
}
// ------------------------------------------------------------------------
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
@ -570,7 +585,6 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis
// authentication activity has returned. mLogin will continue authentication
mLogin.onActivityResult(resultCode, data);
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
@ -626,6 +640,34 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis
}
}
private void deleteUpdateFile() {
File file = new File(getExternalFilesDir(null).toString() + "/iitcUpdate.apk");
if (file != null) file.delete();
}
public void updateIitc(String url) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("downloading IITCm update apk...");
request.setTitle("IITCm Update");
request.allowScanningByMediaScanner();
Uri fileUri = Uri.parse("file://" + getExternalFilesDir(null).toString() + "/iitcUpdate.apk");
request.setDestinationUri(fileUri);
// remove old update file...we don't want to spam the external storage
deleteUpdateFile();
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
}
private void installIitcUpdate() {
String iitcUpdatePath = getExternalFilesDir(null).toString() + "/iitcUpdate.apk";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(iitcUpdatePath)), "application/vnd.android.package-archive");
startActivity(intent);
// finish app, because otherwise it gets killed on update
finish();
}
/**
* @see getNavigationHelper()
* @deprecated ActionBar related stuff should be handled by IITC_NavigationHelper

View File

@ -21,6 +21,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
@ -103,6 +104,11 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity {
}
}
@Override
protected boolean isValidFragment(String s) {
return true;
}
// called by Plugins Fragment
public static ArrayList<IITC_PluginPreference> getPluginPreference(String key) {
return sPlugins.get(key);
@ -193,29 +199,12 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity {
void addPluginPreference(String src, String plugin_key, boolean user) {
// now parse plugin name, description and category
String header = src.substring(src.indexOf("==UserScript=="),
src.indexOf("==/UserScript=="));
// remove new line comments and replace with space
// this way we get double spaces instead of newline + double slash
header = header.replace("\n//", " ");
// get a list of key-value...split on multiple spaces
String[] attributes = header.split(" +");
String plugin_name = "not found";
String plugin_desc = "not found";
String plugin_cat = "Misc";
for (int j = 0; j < attributes.length; j++) {
// search for name and use the value
if (attributes[j].equals("@name")) {
plugin_name = attributes[j + 1];
}
if (attributes[j].equals("@description")) {
plugin_desc = attributes[j + 1];
}
if (attributes[j].equals("@category")) {
plugin_cat = attributes[j + 1];
}
}
// parse plugin name, description and category
// we need default versions here otherwise iitcm may crash
HashMap<String,String> info = IITC_WebViewClient.getScriptInfo(src);
String plugin_name = info.get("name");
String plugin_cat = info.get("category");
String plugin_desc = info.get("description");
// remove IITC plugin prefix from plugin_name
plugin_name = plugin_name.replace("IITC Plugin: ", "");

View File

@ -16,6 +16,7 @@ import android.view.View;
import android.view.WindowManager;
import android.webkit.ConsoleMessage;
import android.webkit.GeolocationPermissions;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
@ -138,24 +139,9 @@ public class IITC_WebView extends WebView {
@Override
public void loadUrl(String url) {
// if in edit text mode, don't load javascript otherwise the keyboard closes.
HitTestResult testResult = getHitTestResult();
if (url.startsWith("javascript:") && testResult != null &&
testResult.getType() == HitTestResult.EDIT_TEXT_TYPE) {
// let window.show(...) interupt input
// window.show(...) is called if one of the action bar buttons
// is clicked
if (!url.startsWith("javascript: window.show(")) {
Log.d("iitcm", "in insert mode. do not load script.");
return;
}
}
// do nothing if script is enabled;
if (mDisableJs) {
Log.d("iitcm", "javascript injection disabled...return");
return;
}
if (!url.startsWith("javascript:")) {
if (url.startsWith("javascript:")) {
loadJS(url.substring("javascript:".length()));
} else {
// force https if enabled in settings
SharedPreferences sharedPref = PreferenceManager
.getDefaultSharedPreferences(getContext());
@ -168,9 +154,38 @@ public class IITC_WebView extends WebView {
// disable splash screen if a http error code is responded
new CheckHttpResponse(mJsInterface, mIitc).execute(url);
Log.d("iitcm", "loading url: " + url);
}
super.loadUrl(url);
}
}
public void loadJS(String js) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(js, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// maybe we want to add stuff here
}
});
} else {
// if in edit text mode, don't load javascript otherwise the keyboard closes.
HitTestResult testResult = getHitTestResult();
if (testResult != null && testResult.getType() == HitTestResult.EDIT_TEXT_TYPE) {
// let window.show(...) interupt input
// window.show(...) is called if one of the action bar buttons
// is clicked
if (!js.startsWith("window.show(")) {
Log.d("iitcm", "in insert mode. do not load script.");
return;
}
}
// do nothing if script is enabled;
if (mDisableJs) {
Log.d("iitcm", "javascript injection disabled...return");
return;
}
super.loadUrl("javascript:" + js);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {

View File

@ -18,11 +18,14 @@ import android.widget.Toast;
import com.cradle.iitc_mobile.async.UrlContentToString;
import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
@ -39,6 +42,7 @@ public class IITC_WebViewClient extends WebViewClient {
private String mIitcScript = null;
private String mIitcPath = null;
private boolean mIitcInjected = false;
private final Context mContext;
public IITC_WebViewClient(Context c) {
@ -48,23 +52,49 @@ public class IITC_WebViewClient extends WebViewClient {
}
public String getIITCVersion() {
HashMap<String, String> map = getScriptInfo(mIitcScript);
return map.get("version");
}
// static method because we use it in IITC_PluginPreferenceActivity too
public static HashMap<String, String> getScriptInfo(String js) {
HashMap<String, String> map = new HashMap<String, String>();
String header = "";
if (mIitcScript != null) {
header = mIitcScript.substring(mIitcScript.indexOf("==UserScript=="),
mIitcScript.indexOf("==/UserScript=="));
if (js != null) {
header = js.substring(js.indexOf("==UserScript=="),
js.indexOf("==/UserScript=="));
}
// remove new line comments
header = header.replace("\n//", "");
header = header.replace("\n//", " ");
// get a list of key-value
String[] attributes = header.split(" +");
String iitc_version = "not found";
// add default values
map.put("version", "not found");
map.put("name", "unknown");
map.put("description", "");
map.put("category", "Misc");
// add parsed values
for (int i = 0; i < attributes.length; i++) {
// search for version and use the value
// search for attributes and use the value
if (attributes[i].equals("@version")) {
iitc_version = attributes[i + 1];
map.put("version", attributes[i + 1]);
}
if (attributes[i].equals("@name")) {
map.put("name", attributes[i + 1]);
}
if (attributes[i].equals("@description")) {
map.put("description", attributes[i + 1]);
}
if (attributes[i].equals("@category")) {
map.put("category", attributes[i + 1]);
}
}
return iitc_version;
return map;
}
public String getGmInfoJson(HashMap<String, String> map) {
JSONObject jObject = new JSONObject(map);
return "{\"script\":" + jObject.toString() + "}";
}
public void loadIITC_JS(Context c) throws java.io.IOException {
@ -112,6 +142,7 @@ public class IITC_WebViewClient extends WebViewClient {
} else {
js = this.fileToString("total-conversion-build.user.js", true);
}
mIitcInjected = false;
}
PackageManager pm = mContext.getPackageManager();
@ -131,9 +162,8 @@ public class IITC_WebViewClient extends WebViewClient {
"window.showLayerChooser = false");
}
// IITC expects to be injected after the DOM has been loaded completely.
// since it is injected with the onPageFinished() event, no further delay is necessary.
this.mIitcScript = js;
String gmInfo = "GM_info=" + getGmInfoJson(getScriptInfo(js)) + "\n";
this.mIitcScript = gmInfo + js;
}
@ -148,8 +178,10 @@ public class IITC_WebViewClient extends WebViewClient {
public void onPageFinished(WebView view, String url) {
if (url.startsWith("http://www.ingress.com/intel")
|| url.startsWith("https://www.ingress.com/intel")) {
if (mIitcInjected) return;
Log.d("iitcm", "injecting iitc..");
view.loadUrl("javascript: " + this.mIitcScript);
mIitcInjected = true;
loadPlugins(view);
}
super.onPageFinished(view, url);
@ -163,6 +195,7 @@ public class IITC_WebViewClient extends WebViewClient {
Log.d("iitcm", "Login requested: " + realm + " " + account + " " + args);
Log.d("iitcm", "logging in...updating caching mode");
((IITC_WebView) view).updateCaching(true);
mIitcInjected = false;
//((IITC_Mobile) mContext).onReceivedLoginRequest(this, view, realm, account, args);
}
@ -205,7 +238,8 @@ public class IITC_WebViewClient extends WebViewClient {
if (js.equals("false")) {
return false;
} else {
view.loadUrl("javascript:" + js);
String gmInfo = "GM_info=" + getGmInfoJson(getScriptInfo(js)) + "\n";
view.loadUrl("javascript:" + gmInfo + js);
}
return true;
}

View File

@ -152,11 +152,19 @@ public class IntentListView extends ListView {
ResolveInfo info = activityList.get(i);
ActivityInfo activity = info.activityInfo;
// fix bug in PackageManager - a replaced package name might cause non-exported intents to appear
if (!activity.exported && !activity.packageName.equals(packageName)) {
activityList.remove(i);
i--;
continue;
}
// remove all IITCm intents, except for SendToClipboard in case Drive is not installed
if (activity.packageName.equals(packageName)) {
if (hasCopyIntent || !activity.name.equals(SendToClipboard.class.getCanonicalName())) {
activityList.remove(i);
i--;
continue;
}
}
}

View File

@ -1,8 +1,8 @@
// ==UserScript==
// @id overlay-kml@danielatkins
// @name IITC plugin: overlay KML
// @category Info
// @version 0.1.@@DATETIMEVERSION@@
// @category Layer
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@

View File

@ -0,0 +1,174 @@
// ==UserScript==
// ==UserScript==
// @id iitc-plugin-bing-maps
// @name IITC plugin: Bing maps
// @category Map Tiles
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Add the maps.bing.com map layers (
// @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 ////////////////////////////////////////////////////////
window.plugin.mapBing = function() {};
window.plugin.mapBing.setupBingLeaflet = function() {
//---------------------------------------------------------------------
// https://github.com/shramov/leaflet-plugins/blob/master/layer/tile/Bing.js
L.BingLayer = L.TileLayer.extend({
options: {
subdomains: [0, 1, 2, 3],
type: 'Aerial',
attribution: 'Bing',
culture: ''
},
initialize: function(key, options) {
L.Util.setOptions(this, options);
this._key = key;
this._url = null;
this.meta = {};
this.loadMetadata();
},
tile2quad: function(x, y, z) {
var quad = '';
for (var i = z; i > 0; i--) {
var digit = 0;
var mask = 1 << (i - 1);
if ((x & mask) != 0) digit += 1;
if ((y & mask) != 0) digit += 2;
quad = quad + digit;
}
return quad;
},
getTileUrl: function(p, z) {
var z = this._getZoomForUrl();
var subdomains = this.options.subdomains,
s = this.options.subdomains[Math.abs((p.x + p.y) % subdomains.length)];
return this._url.replace('{subdomain}', s)
.replace('{quadkey}', this.tile2quad(p.x, p.y, z))
.replace('{culture}', this.options.culture);
},
loadMetadata: function() {
// TODO? modify this to cache the metadata in - say - sessionStorage? localStorage?
var _this = this;
var cbid = '_bing_metadata_' + L.Util.stamp(this);
window[cbid] = function (meta) {
_this.meta = meta;
window[cbid] = undefined;
var e = document.getElementById(cbid);
e.parentNode.removeChild(e);
if (meta.errorDetails) {
alert("Got metadata" + meta.errorDetails);
return;
}
_this.initMetadata();
};
var url = "//dev.virtualearth.net/REST/v1/Imagery/Metadata/" + this.options.type + "?include=ImageryProviders&jsonp=" + cbid + "&key=" + this._key;
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
script.id = cbid;
document.getElementsByTagName("head")[0].appendChild(script);
},
initMetadata: function() {
var r = this.meta.resourceSets[0].resources[0];
this.options.subdomains = r.imageUrlSubdomains;
this._url = r.imageUrl;
this._providers = [];
for (var i = 0; i < r.imageryProviders.length; i++) {
var p = r.imageryProviders[i];
for (var j = 0; j < p.coverageAreas.length; j++) {
var c = p.coverageAreas[j];
var coverage = {zoomMin: c.zoomMin, zoomMax: c.zoomMax, active: false};
var bounds = new L.LatLngBounds(
new L.LatLng(c.bbox[0]+0.01, c.bbox[1]+0.01),
new L.LatLng(c.bbox[2]-0.01, c.bbox[3]-0.01)
);
coverage.bounds = bounds;
coverage.attrib = p.attribution;
this._providers.push(coverage);
}
}
this._update();
},
_update: function() {
if (this._url == null || !this._map) return;
this._update_attribution();
L.TileLayer.prototype._update.apply(this, []);
},
_update_attribution: function() {
var bounds = this._map.getBounds();
var zoom = this._map.getZoom();
for (var i = 0; i < this._providers.length; i++) {
var p = this._providers[i];
if ((zoom <= p.zoomMax && zoom >= p.zoomMin) &&
bounds.intersects(p.bounds)) {
if (!p.active)
this._map.attributionControl.addAttribution(p.attrib);
p.active = true;
} else {
if (p.active)
this._map.attributionControl.removeAttribution(p.attrib);
p.active = false;
}
}
},
onRemove: function(map) {
for (var i = 0; i < this._providers.length; i++) {
var p = this._providers[i];
if (p.active) {
this._map.attributionControl.removeAttribution(p.attrib);
p.active = false;
}
}
L.TileLayer.prototype.onRemove.apply(this, [map]);
}
});
//---------------------------------------------------------------------
}
window.plugin.mapBing.setup = function() {
window.plugin.mapBing.setupBingLeaflet();
//set this to your API key
var bingApiKey = 'ArR2hTa2C9cRQZT-RmgrDkfvh3PwEVRl0gB34OO4wJI7vQNElg3DDWvbo5lfUs3p';
var bingTypes = {
'Road': "Road",
'Aerial': "Aerial",
'AerialWithLabels': "Aerial with labels",
};
for (type in bingTypes) {
var name = bingTypes[type];
var bingMap = new L.BingLayer(bingApiKey, {type: type, maxZoom:20});
layerChooser.addBaseLayer(bingMap, 'Bing '+name);
}
};
var setup = window.plugin.mapBing.setup;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,48 @@
// ==UserScript==
// @id iitc-plugin-nokia-ovi-maps
// @name IITC plugin: Nokia OVI maps
// @category Map Tiles
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Add various map layers from Nokia OVI Maps
// @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 ////////////////////////////////////////////////////////
window.plugin.mapNokiaOvi = function() {};
window.plugin.mapNokiaOvi.setup = function() {
//the list of styles you'd like to see
var oviStyles = {
'normal.day': "Normal",
'normal.day.grey': "Normal (grey)",
'normal.day.transit': "Normal (transit)",
'satellite.day': "Satellite",
'terrain.day': "Terrain",
};
var oviOpt = {attribution: 'Imagery © Nokia OVI', maxZoom: 20};
$.each(oviStyles, function(key,value) {
oviOpt['style'] = key;
var oviMap = new L.TileLayer('http://maptile.maps.svc.ovi.com/maptiler/maptile/newest/{style}/{z}/{x}/{y}/256/png8', oviOpt);
layerChooser.addBaseLayer(oviMap, 'Nokia OVI '+value);
});
};
var setup = window.plugin.mapNokiaOvi.setup;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,67 @@
// ==UserScript==
// @id iitc-plugin-basemap-stamen@jonatkins
// @name IITC plugin: Map layers from stamen.com
// @category Map Tiles
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Adds the 'Toner' and 'Watercolor' map layers from maps.stamen.com
// @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 ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.mapTileStamen = function() {};
window.plugin.mapTileStamen.addLayer = function() {
var types = {
'toner': [ 'Toner', 'png', 0, 20 ],
// 'toner-hybrid': [ ' Toner Hybrid', 'png', 0, 20 ], // transparent layer. could be usefun over satelliate imagery or similar
// 'toner-labels': [ 'Toner Labels', 'png', 0, 20 ], // transparent layer. could be usefun over satelliate imagery or similar
// 'toner-lines': [ 'Toner Lines', 'png', 0, 20 ], // transparent layer. could be usefun over satelliate imagery or similar
'toner-background': [ 'Toner Background', 'png', 0, 20 ],
'toner-lite': [ 'Toner Lite', 'png', 0, 20 ],
'watercolor': [ 'Watercolor', 'jpg', 1, 16 ],
};
var baseUrl = window.location.protocol == 'https:' ? 'https://stamen-tiles-{s}.a.ssl.fastly.net/' : 'http://{s}.tile.stamen.com/';
for (var layer in types) {
var info = types[layer];
var name = info[0];
var type = info[1];
var minZoom = info[2];
var maxZoom = info[3];
var mapLayer = new L.TileLayer (baseUrl+'{layer}/{z}/{x}/{y}.{type}', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.',
subdomains: 'abcd',
layer: layer,
type: type,
minZoom: minZoom,
maxZoom: maxZoom
});
layerChooser.addBaseLayer(mapLayer,'Stamen '+name);
}
};
var setup = window.plugin.mapTileStamen.addLayer;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-player-tracker@breunigs
// @name IITC Plugin: Player tracker
// @category Layer
// @version 0.9.6.@@DATETIMEVERSION@@
// @version 0.10.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -62,12 +62,22 @@ window.plugin.playerTracker.setup = function() {
});
}
});
plugin.playerTracker.oms = new OverlappingMarkerSpiderfier(map);
plugin.playerTracker.oms = new OverlappingMarkerSpiderfier(map, {keepSpiderfied: true, legWeight: 3.5});
plugin.playerTracker.oms.legColors = {'usual': '#FFFF00', 'highlighted': '#FF0000'};
plugin.playerTracker.oms.legWeight = 3.5;
var playerPopup = new L.Popup({offset: L.point([1,-34])});
plugin.playerTracker.oms.addListener('click', function(player) {
window.renderPortalDetails(player.options.referenceToPortal);
if (player.options.desc) {
playerPopup.setContent(player.options.desc);
playerPopup.setLatLng(player.getLatLng());
map.openPopup(playerPopup);
}
});
plugin.playerTracker.oms.addListener('spiderfy', function(markers) {
map.closePopup();
});
addHook('publicChatDataAvailable', window.plugin.playerTracker.handleData);
@ -226,6 +236,7 @@ window.plugin.playerTracker.processNewData = function(data) {
}
window.plugin.playerTracker.getLatLngFromEvent = function(ev) {
//TODO? add weight to certain events, or otherwise prefer them, to give better locations?
var lats = 0;
var lngs = 0;
$.each(ev.latlngs, function() {
@ -248,6 +259,8 @@ window.plugin.playerTracker.ago = function(time, now) {
}
window.plugin.playerTracker.drawData = function() {
var isTouchDev = window.isTouchDevice();
var gllfe = plugin.playerTracker.getLatLngFromEvent;
var polyLineByAgeEnl = [[], [], [], []];
@ -275,37 +288,46 @@ window.plugin.playerTracker.drawData = function() {
polyLineByAgeEnl[ageBucket].push(line);
}
// tooltip for marker
var evtsLength = playerData.events.length;
var last = playerData.events[evtsLength-1];
var ago = plugin.playerTracker.ago;
// tooltip for marker - no HYML - and not shown on touchscreen devices
var tooltip = isTouchDev ? '' : (playerData.nick+', '+ago(last.time, now)+' ago');
// popup for marker
var cssClass = playerData.team === 'RESISTANCE' ? 'res' : 'enl';
var title = '<span class="nickname '+ cssClass+'" style="font-weight:bold;">' + playerData.nick + '</span>';
var popup = '<span class="nickname '+cssClass+'" style="font-weight:bold;">' + playerData.nick + '</span>';
if(window.plugin.guessPlayerLevels !== undefined &&
window.plugin.guessPlayerLevels.fetchLevelByPlayer !== undefined) {
var playerLevel = window.plugin.guessPlayerLevels.fetchLevelByPlayer(pguid);
if(playerLevel !== undefined) {
title += '<span style="font-weight:bold;margin-left:10px;">Level '
popup += '<span style="font-weight:bold;margin-left:10px;">Level '
+ playerLevel
+ ' (guessed)'
+ '</span>';
} else {
title += '<span style="font-weight:bold;margin-left:10px;">Level unknown</span>'
popup += '<span style="font-weight:bold;margin-left:10px;">Level unknown</span>'
}
}
title += '\n'
+ ago(last.time, now) + ' ago\n'
popup += '<br>'
+ ago(last.time, now) + ' ago<br>'
+ window.chat.getChatPortalName(last);
// show previous data in tooltip
var minsAgo = '\t<span style="white-space: nowrap;"> ago</span>\t';
if(evtsLength >= 2)
title += '\n&nbsp;\nprevious locations:\n';
if(evtsLength >= 2) {
popup += '<br>&nbsp;<br>previous locations:<br>'
+ '<table style="border-spacing:0">';
}
for(var i = evtsLength - 2; i >= 0 && i >= evtsLength - 10; i--) {
var ev = playerData.events[i];
title += ago(ev.time, now) + minsAgo + window.chat.getChatPortalName(ev) + '\n';
popup += '<tr align="left"><td>' + ago(ev.time, now) + '</td>'
+ '<td>ago</td>'
+ '<td>' + window.chat.getChatPortalName(ev) + '</td></tr>';
}
if(evtsLength >= 2)
popup += '</table>';
// calculate the closest portal to the player
var eventPortal = []
@ -329,13 +351,18 @@ window.plugin.playerTracker.drawData = function() {
// marker itself
var icon = playerData.team === 'RESISTANCE' ? new plugin.playerTracker.iconRes() : new plugin.playerTracker.iconEnl();
var m = L.marker(gllfe(last), {title: title, icon: icon, referenceToPortal: closestPortal, opacity: absOpacity});
// ensure tooltips are closed, sometimes they linger
m.on('mouseout', function() { $(this._icon).tooltip('close'); });
// as per OverlappingMarkerSpiderfier docs, click events (popups, etc) must be handled via it rather than the standard
// marker click events. so store the popup text in the options, then display it in the oms click handler
var m = L.marker(gllfe(last), {icon: icon, referenceToPortal: closestPortal, opacity: absOpacity, desc: popup, title: tooltip});
// m.bindPopup(title);
m.addTo(playerData.team === 'RESISTANCE' ? plugin.playerTracker.drawnTracesRes : plugin.playerTracker.drawnTracesEnl);
plugin.playerTracker.oms.addMarker(m);
// jQueryUI doesnt automatically notice the new markers
if (!isTouchDev) {
window.setupTooltips($(m._icon));
}
});
// draw the poly lines to the map
@ -372,13 +399,6 @@ window.plugin.playerTracker.handleData = function(data) {
plugin.playerTracker.discardOldData();
plugin.playerTracker.processNewData(data);
// remove old popups
plugin.playerTracker.drawnTracesEnl.eachLayer(function(layer) {
if(layer._icon) $(layer._icon).tooltip('destroy');
});
plugin.playerTracker.drawnTracesRes.eachLayer(function(layer) {
if(layer._icon) $(layer._icon).tooltip('destroy');
});
plugin.playerTracker.oms.clearMarkers();
plugin.playerTracker.drawnTracesEnl.clearLayers();
plugin.playerTracker.drawnTracesRes.clearLayers();

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @category Info
// @version 0.0.17.@@DATETIMEVERSION@@
// @version 0.0.18.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -212,10 +212,13 @@ window.plugin.portalslist.displayPL = function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,2));
});
//run the name resolving process
resolvePlayerNames();
//debug tools
//end = new Date().getTime();
//console.log('***** end : ' + end + ' and Elapse : ' + (end - start));
}
}
window.plugin.portalslist.portalTable = function(sortBy, sortOrder, filter) {
// sortOrder <0 ==> desc, >0 ==> asc, i use sortOrder * -1 to change the state

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-scoreboard@vita10gy
// @name IITC plugin: show a localized scoreboard.
// @category Info
// @version 0.1.8.@@DATETIMEVERSION@@
// @version 0.1.9.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -291,6 +291,9 @@ window.plugin.scoreboard.display = function() {
$(document).on('click', '#players table th', function() {
$('#players').html(window.plugin.scoreboard.playerTable($(this).data('sort')));
});
//run the name resolving process
resolvePlayerNames();
}
window.plugin.scoreboard.portalDistance = function(portalAE6Location, portalBE6Location) {

View File

@ -0,0 +1,314 @@
// ==UserScript==
// @id iitc-plugin-update-check@jonatkins
// @name IITC plugin: Check for updates
// @category Misc
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] **WORK IN PROGRESS** Check for updates for IITC and plugins against http://iitc.jonatkins.com/. Can also report status messages for known IITC issues.
// @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 ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.updateCheck = function() {};
window.plugin.updateCheck.versionDataLoading = false;
window.plugin.updateCheck.getUrl = function(callback) {
var url = 'http://iitc.jonatkins.com/versioncheck.php'
+ '?build=@@BUILDNAME@@'
+ '&mobile='+((typeof android !== 'undefined' && android)?'1':'0')
+ '&ts='+Date.now(); // append timestamp - ensures no cacheing of old data, even on mobile with the aggressive cache code
if (callback) {
url = url + '&callback='+callback
}
return url;
}
window.plugin.updateCheck.versionCompare = function(a,b) {
a = a.split('.');
b = b.split('.');
// adding dummy -1 entries to both split arrays simplifies comparisons
a.push(-1);
b.push(-1);
var minlen = Math.min(a.length, b.length);
for (var i=0; i<minlen; i++) {
var anum = parseInt(a[i]);
var bnum = parseInt(b[i]);
if (anum != bnum) {
return bnum-anum;
}
}
return 0;
}
window.plugin.updateCheck.loadVersionData = function() {
if (!window.plugin.updateCheck.versionDataLoading) {
window.plugin.updateCheck.versionDataLoading = true;
//TODO: IITC Mobile-specific parameter, to retrieve the mobile app version rather than the script versions
//also
// JSInterface public void updateIitc(String fileUrl)
//call on the android object to be able to download+install the android app.
var s = document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src', window.plugin.updateCheck.getUrl('window.plugin.updateCheck.versionDataCallback'));
s.setAttribute('id','update-check-script-tag');
document.getElementsByTagName("head")[0].appendChild(s);
} else {
// else we're already loading the script and it hasn't completed - do nothing
console.warn('update-check: already loading data - cannot load again');
}
}
window.plugin.updateCheck.versionDataCallback = function(data) {
// data loaded - flag it's not loading any more and remove the script tag
window.plugin.updateCheck.versionDataLoading = false;
var s = document.getElementById('update-check-script-tag');
if (s) {
s.parentNode.removeChild(s);
}
window.plugin.updateCheck.showReport(data);
}
window.plugin.updateCheck.versionHTML = function(ver) {
var re = new RegExp ('^([0-9]+\\.[0-9]+\\.[0-9]+)(\\.2[0-9][0-9][0-9][01][0-9][0123][0-9]\\.[0-9]+)$');
var match = ver.match(re);
if (match) {
return match[1]+'<small>'+match[2]+'</small>';
} else {
return ver;
}
}
window.plugin.updateCheck.compareDetails = function(web_version, script_version) {
// compare the local script version data with the website version data
// and return an object with the results
var result = {};
result.webUrl = web_version.pageUrl;
result.downloadUrl = web_version.downloadUrl;
result.webVersion = web_version.version;
result.localVersion = script_version.script && script_version.script.version;
if (result.localVersion && result.webVersion) {
result.comp = window.plugin.updateCheck.versionCompare (result.localVersion, result.webVersion);
result.outOfDate = result.comp>0;
result.upToDate = result.comp==0;
result.localNewer = result.comp<0;
}
var webVerHTML = result.webVersion && window.plugin.updateCheck.versionHTML(result.webVersion);
var localVerHTML = result.localVersion && window.plugin.updateCheck.versionHTML(result.localVersion);
// var webLinkInstallHTML = '';
// if (result.downloadUrl && result.webUrl) {
// webLinkInstallHTML = '<a href="'+result.webUrl+'" title="Web page" target="_blank">web</a> '
// + '<a href="'+result.downloadUrl+'" title="Install" target="_blank">install</a>';
// }
if (!result.localVersion) {
result.html = '<span class="help" title="Your version unknown\nLatest version '+webVerHTML+'">version check failed</span>';
} else if (!result.webVersion) {
result.html = '<span class="help" title="Your version '+localVerHTML+'\nNo version from update check server">version check failed</span>';
} else if (result.upToDate) {
result.html = '<span class="help" title="Version '+localVerHTML+'">up to date</span>';
} else if (result.outOfDate) {
result.html = '<span class="help" title="Your version '+localVerHTML+'\nLatest version '+webVerHTML+'">out of date</span>';
} else if (result.localNewer) {
result.html = localVerHTML+' is newer than '+webVerHTML+'(?!)';
} else {
console.warn ('Unknown case of version combinations!');
result.html = '<span class="help" title="Your version '+localVerHTML+'\nLatest version '+webVerHTML+'">version check failed(!?)</span>';
}
return result;
}
window.plugin.updateCheck.showReport = function(data) {
var result = '<b>WORK IN PROGRESS</b>';
if (data.error) {
result += '<div><b>Error checking for updates</b><br>'+data.error+'</div>';
} else {
if (data.name) {
result += '<div>IITC update check: '+data.name+'</div>';
}
if (typeof android !== 'undefined' && android) {
// mobile app version check
var ourVerCode = android.getVersionCode && android.getVersionCode() || 0;
var ourVerName = android.getVersionName && android.getVersionName() || '(unknown)';
if (data.mobile) {
var latestVerCode = parseInt(data.mobile.versioncode);
var latestVerName = data.mobile.versionstr;
var webLink = '';
if (data.mobile.pageurl) webLink = '<a href="'+data.mobile.pageurl+'" target="_blank">web</a>';
var downloadLink = '';
if (data.mobile.downloadurl) downloadLink = '<a href="'+data.mobile.downloadurl+'">download</a>';
if (data.mobile.downloadurl && android.updateIitc) downloadLink = '<a onclick="android.updateIitc(\''+data.mobile.downloadurl+'\')">install</a>';
if (ourVerCode == latestVerCode) {
// up to date
result += '<div>IITC Mobile is up to date - version <span title="ver code "'+ourVerCode+'">'+ourVerName+'</span> '+webLink+'</div>';
} else if (ourVerCode < latestVerCode) {
// out of date
result += '<div>IITC Mobile is out of date. Current version <span title="ver code "'+ourVerCode+'">'+ourVerName+'</span>, '
+ 'Available version <span title="ver code "'+latestVerCode+'">'+latestVerName+'</span>. '+webLink+' '+downloadLink+'</div>';
} else {
// local version newer?!
result += '<div>IITC Mobile version newer than latest on server?! Current version <span title="ver code "'+ourVerCode+'">'+ourVerName+'</span>, '
+ 'Available version <span title="ver code "'+latestVerCode+'">'+latestVerName+'</span>.</div>';
}
} else {
result += '<div>Warning: no version data for mobile app found in response</div>';
}
} else {
// desktop userscript version check
if (data.iitc && window.script_info) {
var compare = window.plugin.updateCheck.compareDetails(data.iitc, window.script_info);
result += '<div>IITC Main script: '+compare.html+'</div>';
} else {
if (!data.iitc) {
result += '<div>Warning: no version information for main IITC script found in response</div>';
}
if (!window.script_info) {
result += '<div>Warning: your IITC script does not contain version data</div>';
}
}
}
if (data.plugins && window.bootPlugins) {
var plugins = { upToDate: [], outOfDate: [], other: [] };
if (window.bootPlugins.length == 0) {
result += '<li>No plugins installed</li>';
} else {
for (var i=0; i<window.bootPlugins.length; i++) {
var pluginStatus = { index: i, status: 'other' };
var info = window.bootPlugins[i].info;
pluginStatus.name = info.script && info.script.name || info.pluginId || ('(unknown plugin index '+i+')');
pluginStatus.name = pluginStatus.name.replace ( /^IITC plugin: /i, '' );
if (info && info.pluginId) {
var webinfo = data.plugins[info.pluginId];
if (webinfo) {
var compare = window.plugin.updateCheck.compareDetails(webinfo,info);
pluginStatus.compare = compare;
if (compare.upToDate) {
pluginStatus.status = 'upToDate';
} else if (compare.outOfDate) {
pluginStatus.status = 'outOfDate';
}
}
}
plugins[pluginStatus.status].push(pluginStatus);
}
}
result += '<div>Plugins:<table>';
var formatRow = function(p,weblink,downloadlink) {
var status = p.status;
var name = p.name;
var statustext = p.compare && p.compare.html || '-';
var links = [];
if (weblink && p.compare && p.compare.webUrl) links.push('<a href="'+p.compare.webUrl+'" target="_blank">web</a>');
if (downloadlink && p.compare && p.compare.downloadUrl) links.push('<a href="'+p.compare.downloadUrl+'" target="_blank">download</a>');
//now convert to text
links = links && links.join(' ') || '-';
return '<tr class="'+status+'"><td>'+name+'</td><td>'+statustext+'</td><td>'+links+'</td></tr>';
}
result += '<tr><th colspan="3">Out of date</th></tr>';
for (var i in plugins.outOfDate) {
result += formatRow (plugins.outOfDate[i],true,true);
}
if (plugins.outOfDate.length==0) {
result += '<tr><td colspan="3">no plugins</td></tr>';
}
result += '<tr><th colspan="3">Up To Date</th></tr>';
for (var i in plugins.upToDate) {
result += formatRow (plugins.upToDate[i],true,false);
}
if (plugins.upToDate.length==0) {
result += '<tr><td colspan="3">no plugins</td></tr>';
}
result += '<tr><th colspan="3">Other</th></tr>';
for (var i in plugins.other) {
result += formatRow (plugins.other[i],true,false);
}
if (plugins.other.length==0) {
result += '<tr><td colspan="3">no plugins</td></tr>';
}
result += '</table</div>';
}
}
dialog({
width: 700,
title: 'Update check',
html: result
});
}
window.plugin.updateCheck.open = function() {
// TODO? open a dialog/show a message indicating that the update check is in progress, before the data is loaded?
// TODO? prevent loading the version data every time - cache it, with a user option to force fresh data
window.plugin.updateCheck.loadVersionData();
}
window.plugin.updateCheck.setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.updateCheck.open()" title="Check for IITC updates">Update check</a>');
};
var setup = window.plugin.updateCheck.setup;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -982,3 +982,53 @@ td + td {
display: none;
}
/* leaflet popups - restyle to match the theme of IITC */
#map .leaflet-popup {
pointer-events: none;
}
#map .leaflet-popup-content-wrapper {
border-radius: 0px;
-webkit-border-radius: 0px;
border: 1px solid #20A8B1;
background: #0e3d4e;
pointer-events: auto;
}
#map .leaflet-popup-content {
color: #ffce00;
margin: 5px 8px;
}
#map .leaflet-popup-close-button {
padding: 2px 1px 0 0;
font-size: 12px;
line-height: 8px;
width: 10px;
height: 10px;
pointer-events: auto;
}
#map .leaflet-popup-tip {
/* change the tip from an arrow to a simple line */
background: #20A8B1;
width: 1px;
height: 20px;
padding: 0;
margin: 0 0 0 20px;
-webkit-transform: none;
-moz-transform: none;
-ms-transform: none;
-o-transform: none;
transform: none;
}
/* misc */
.no-pointer-events {
pointer-events: none;
}

View File

@ -33,10 +33,10 @@ function loadPopularity()
function popularity_cmp ( $a, $b )
{
if ( $a['popularity'] == $b['popularity'] )
if ( @$a['popularity'] == @$b['popularity'] )
return 0;
// sort from highest to lowest
return ($a['popularity'] > $b['popularity']) ? -1 : 1;
return (@$a['popularity'] > @$b['popularity']) ? -1 : 1;
}

View File

@ -19,8 +19,6 @@ function getMobileVersion ( $apkfile )
$archive = $apkinfo->getApkArchive();
$stream = $archive->getStream ( "assets/total-conversion-build.user.js" );
if ( ! $stream )
$stream = $archive->getStream ( "assets/iitc.js" );
if ( $stream )
{

View File

@ -68,6 +68,20 @@ if ( file_exists ( 'tracking.php' ) )
- a place to ask for help and discuss with other users.
</div>
<!-- **** alert box when standard intel site changes **** -->
<?php
if ( file_exists ( "flag-stock-site-changed.txt" ) )
{
?>
<div class="alert alert-block alert-error">
<b>Note</b>: A change has been detected to the standard intel website. Such changes usually break IITC.
The developers have been notified of the update, and will be looking to fix things as soon as possible.
See the <a href="https://plus.google.com/communities/105647403088015055797">IITC Community</a>
for the latest details.
</div>
<?php
}
?>
<!--
<div class="alert alert-block alert-error">
<b>IITC has yet again been broken by changes Niantic have made.</b> Further information/discussion on

View File

@ -13,10 +13,50 @@ offers many more features. It is available for
<h3>Latest news</h3>
<h4>11th November 2013</h4>
<p>
IITC 0.15.0 and IITC Mobile 0.9 have just been released. This update fixes things to work with the latest changes
to the standard intel site. Also
<ul>
<li>Support for Jarvis shards (and other future artifacts)</li>
<li>New base map plugins - for <a href="http://maps.stamen.com/">maps.stamen.com/</a> and Bing maps.</li>
</ul>
</p>
<h4>7th November 2013</h4>
<p>
IITC 0.14.6 and IITC Mobile 0.7.7.2 released. Another change needed to match a minor update to the standard intel site.
</p>
<h4>6th November 2013</h4>
<p>
IITC 0.14.5 and IITC Mobile 0.7.7.1 have been released. This contains a fix to work with the latest intel site updates.
Other than this, it is identical to the 0.14.4/0.7.7 release.
</p>
<h4>29th October 2013</h4>
<p>
IITC 0.14.4 and IITC Mobile 0.7.7 have just been released. A critical update required to work with changes made to the
standard intel site.
standard intel site. Changes include
<ul>
<li>Fix to geodesic circle drawing. They were not correctly distorted, leading to incorrect link ranges drawn on the map.</li>
<li>Bookmarks plugin: add layer and highlighter to indicate bookmarked portals</li>
<li>Player tracker plugin: markers fade for older activity, and separate layers for each faction</li>
<li>The 'About IITC' dialog now lists which plugins are installed. This may not work correctly for 3rd party plugins at this time</li>
<li>Mobile:
<ul>
<li>Custom fullscreen preferences</li>
<li>Install to SD Card</li>
<li>Cache move to SD card option (hence the new permissions)</li>
</ul>
</li>
<li>... and, as always, various bugfixes and improvements.</li>
</ul>
</p>
<p>
<b>3RD PARTY PLUGIN AUTHORS</b>: The plugin wrapper code has been modified to pass through the additioal version
information. While existing plugins should continue to work, I highly recommend updating the wrapper code in your
scripts to match.
</p>
<h4>16th October 2013</h4>

View File

@ -1,9 +1,49 @@
<h2>News</h2>
<h4>11th November 2013</h4>
<p>
IITC 0.15.0 and IITC Mobile 0.9 have just been released. This update fixes things to work with the latest changes
to the standard intel site. Also
<ul>
<li>Support for Jarvis shards (and other future artifacts)</li>
<li>New base map plugins - for <a href="http://maps.stamen.com/">maps.stamen.com/</a> and Bing maps.</li>
</ul>
</p>
<h4>7th November 2013</h4>
<p>
IITC 0.14.6 and IITC Mobile 0.7.7.2 released. Another change needed to match a minor update to the standard intel site.
</p>
<h4>6th November 2013</h4>
<p>
IITC 0.14.5 and IITC Mobile 0.7.7.1 have been released. This contains a fix to work with the latest intel site updates.
Other than this, it is identical to the 0.14.4/0.7.7 release.
</p>
<h4>29th October 2013</h4>
<p>
IITC 0.14.4 and IITC Mobile 0.7.7 have just been released. A critical update required to work with changes made to the
standard intel site.
standard intel site. Changes include
<ul>
<li>Fix to geodesic circle drawing. They were not correctly distorted, leading to incorrect link ranges drawn on the map.</li>
<li>Bookmarks plugin: add layer and highlighter to indicate bookmarked portals</li>
<li>Player tracker plugin: markers fade for older activity, and separate layers for each faction</li>
<li>The 'About IITC' dialog now lists which plugins are installed. This may not work correctly for 3rd party plugins at this time</li>
<li>Mobile:
<ul>
<li>Custom fullscreen preferences</li>
<li>Install to SD Card</li>
<li>Cache move to SD card option (hence the new permissions)</li>
</ul>
</li>
<li>... and, as always, various bugfixes and improvements.</li>
</ul>
</p>
<p>
<b>3RD PARTY PLUGIN AUTHORS</b>: The plugin wrapper code has been modified to pass through the additioal version
information. While existing plugins should continue to work, I highly recommend updating the wrapper code in your
scripts to match.
</p>
<h4>16th October 2013</h4>

145
website/versioncheck.php Normal file
View File

@ -0,0 +1,145 @@
<?php
include_once "code/userscript.php";
include_once "code/url/url_to_absolute.php";
include_once "code/apk/ApkParser.php";
$response = Array();
$build = $_REQUEST['build'];
$mobile = isset($_REQUEST['mobile']) && $_REQUEST['mobile'];
$details = Array (
'jonatkins' => Array ( # live release
'path' => 'release',
'name' => 'Stable release build',
'web' => 'http://iitc.jonatkins.com/?page=download',
'mobileweb' => 'http://iitc.jonatkins.com/?page=mobile',
),
'jonatkins-test' => Array ( # public test builds
'path' => 'test',
'name' => 'Test build',
'web' => 'http://iitc.jonatkins.com/?page=test',
'mobileweb' => 'http://iitc.jonatkins.com/?page=test#test-mobile',
),
'jonatkins-experimental' => Array ( # rarely used, for features not quite ready for 'test'
'path' => 'experimental',
'name' => 'Experimental build',
'web' => 'http://iitc.jonatkins.com/?page=test&build=experimental',
'mobileweb' => 'http://iitc.jonatkins.com/?page=test&build=experimental#test-mobild',
),
'jonatkins-dev' => Array ( # personal
'path' => 'dev',
'name' => 'Development builds - not for public use',
'web' => 'http://iitc.jonatkins.com/?page=test&build=dev',
'mobileweb' => 'http://iitc.jonatkins.com/?page=test&build=dev#test-mobile',
),
'local' => Array ( # not a real build, but often the default for local development
'path' => NULL,
'name' => 'Local build - no update check available',
),
);
if ( array_key_exists ( $build, $details ) )
{
$info = $details[$build];
$pageurl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? "https" : "http")."://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$response['name'] = $info['name'];
$dir = $info['path'];
if ( $mobile )
{
$apkfile = $dir.'/IITC_Mobile-'.$dir.'.apk';
if ( file_Exists ( $apkfile ) )
{
$apkinfo = new ApkParser ( $apkfile );
$manifest = $apkinfo->getManifest();
$response['mobile'] = Array (
'versionstr' => $manifest->getVersionName(),
'versioncode' => $manifest->getVersionCode(),
'downloadurl' => url_to_absolute ( $pageurl, $apkfile ),
'pageurl' => $info['mobileweb'],
);
$archive = $apkinfo->getApkArchive();
$stream = $archive->getStream ( "assets/total-conversion-build.user.js" );
if ( $stream )
{
$header = loadUserScriptHeader ( $stream );
$response['mobile']['iitc_version'] = $header['@version'];
}
}
else
{
$response['error'] = 'Failed to find .apk file '.$apkfile;
}
}
else
{
// desktop - .user.js scripts
// load main script version
$iitc_details = loadUserScriptHeader ( "$dir/total-conversion-build.user.js" );
$response['iitc'] = Array (
'version' => $iitc_details['@version'],
'downloadUrl' => url_to_absolute ( $pageurl, "$dir/total-conversion-build.user.js" ),
'pageUrl' => url_to_absolute ( $pageurl, $info['web'] ),
);
// and now the plugins
$response['plugins'] = Array();
foreach ( glob ( "$dir/plugins/*.user.js" ) as $path )
{
$basename = basename ( $path, ".user.js" );
$details = loadUserScriptHeader ( $path );
$response['plugins'][$basename] = Array (
'version' => $details['@version'],
'downloadUrl' => url_to_absolute ( $pageurl, "$dir/plugins/$basename.user.js" ),
'pageUrl' => url_to_absolute ( $pageurl, $info['web']."#plugin-$basename" ),
);
}
}
}
else
{
$response['error'] = 'Unsupported build for version check';
}
$data = json_encode ( $response );
# send the response - allow either jsonp (using a 'callback' parameter), or regular json
if ( array_key_exists ( 'callback', $_GET ) )
{
header('Content-Type: text/javascript; charset=utf8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Max-Age: 3628800');
header('Access-Control-Allow-Methods: GET, POST');
$callback = $_GET['callback'];
echo $callback.'('.$data.');';
}
else
{
// normal JSON string
header('Content-Type: application/json; charset=utf8');
echo $data;
}

View File

@ -1,135 +0,0 @@
<?php
$response = Array();
$build = $_REQUEST['build'];
$details = Array (
'jonatkins' => Array ( # live release
'path' => 'release',
'name' => 'Stable release build',
),
'jonatkins-test' => Array ( # public test builds
'path' => 'test',
'name' => 'Test build',
),
'jonatkins-experimental' => Array ( # rarely used, for features not quite ready for 'test'
'path' => 'experimental',
'name' => 'Experimental build',
),
'jonatkins-dev' => Array ( # personal
'path' => 'dev',
'name' => 'Development builds - not for public use',
),
'local' => Array ( # not a real build, but often the default for local development
'path' => NULL,
'name' => 'Local build - no update check available',
),
);
if ( array_key_exists ( $build, $details ) )
{
$info = $details[$build];
$response['buildPath'] = $info['path'];
$response['name'] = $info['name'];
}
else
{
$response['error'] = 'Unsupported build for version check';
}
$data = json_encode ( $response );
$data = indent($data);
# send the response - allow either jsonp (using a 'callback' parameter), or regular json
if ( array_key_exists ( 'callback', $_GET ) )
{
header('Content-Type: text/javascript; charset=utf8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Max-Age: 3628800');
header('Access-Control-Allow-Methods: GET, POST');
$callback = $_GET['callback'];
echo $callback.'('.$data.');';
}
else
{
// normal JSON string
header('Content-Type: application/json; charset=utf8');
echo $data;
}
// http://www.daveperrett.com/articles/2008/03/11/format-json-with-php/
/**
* Indents a flat JSON string to make it more human-readable.
*
* @param string $json The original JSON string to process.
*
* @return string Indented version of the original JSON string.
*/
function indent($json) {
$result = '';
$pos = 0;
$strLen = strlen($json);
$indentStr = ' ';
$newLine = "\n";
$prevChar = '';
$outOfQuotes = true;
for ($i=0; $i<=$strLen; $i++) {
// Grab the next character in the string.
$char = substr($json, $i, 1);
// Are we inside a quoted string?
if ($char == '"' && $prevChar != '\\') {
$outOfQuotes = !$outOfQuotes;
// If this character is the end of an element,
// output a new line and indent the next line.
} else if(($char == '}' || $char == ']') && $outOfQuotes) {
$result .= $newLine;
$pos --;
for ($j=0; $j<$pos; $j++) {
$result .= $indentStr;
}
}
// Add the character to the result string.
$result .= $char;
// If the last character was the beginning of an element,
// output a new line and indent the next line.
if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) {
$result .= $newLine;
if ($char == '{' || $char == '[') {
$pos ++;
}
for ($j = 0; $j < $pos; $j++) {
$result .= $indentStr;
}
}
$prevChar = $char;
}
return $result;
}
?>