diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md
index 81723e1f..edb3f828 100644
--- a/ATTRIBUTION.md
+++ b/ATTRIBUTION.md
@@ -10,5 +10,8 @@ This project is licensed under the permissive [ISC license](http://www.isc.org/d
- [taphold.js by Rich Adams; unknown](https://github.com/richadams/jquery-taphold)
- [L.Control.Pan.js by Kartena AB; same as Leaflet](https://github.com/kartena/Leaflet.Pancontrol)
- [L.Control.Zoomslider.js by Kartena AB; same as Leaflet](https://github.com/kartena/Leaflet.zoomslider)
+- [KML.js by shramov; same as Leaflet](https://github.com/shramov/leaflet-plugins)
+- [leaflet.filelayer.js by shramov; same as Leaflet](https://github.com/shramov/leaflet-plugins)
+- [togeojson.js by shramov; same as Leaflet](https://github.com/shramov/leaflet-plugins)
- StackOverflow-CopyPasta is attributed in the source; [CC-Wiki](https://creativecommons.org/licenses/by-sa/3.0/)
- all Ingress/Niantic related stuff obviously remains non-free and is still copyrighted by Niantic/Google
diff --git a/CONTRIBS.md b/CONTRIBS.md
index 0cfccf65..5ab69b23 100644
--- a/CONTRIBS.md
+++ b/CONTRIBS.md
@@ -8,7 +8,9 @@ So far, these people have contributed:
[ccjon](https://github.com/ccjon),
[cmrn](https://github.com/cmrn),
[epf](https://github.com/epf),
+[fkloft](https://github.com/fkloft),
[Fragger](https://github.com/Fragger),
+[hastarin](https://github.com/hastarin),
[integ3r](https://github.com/integ3r),
[j16sdiz](https://github.com/j16sdiz),
[JasonMillward](https://github.com/JasonMillward),
diff --git a/build.py b/build.py
index 96212c5c..921f0d0a 100755
--- a/build.py
+++ b/build.py
@@ -60,29 +60,38 @@ resourceUrlBase = settings.get('resourceUrlBase')
distUrlBase = settings.get('distUrlBase')
buildMobile = settings.get('buildMobile')
antOptions = settings.get('antOptions','')
+antBuildFile = settings.get('antBuildFile', 'mobile/build.xml');
+
# plugin wrapper code snippets. handled as macros, to ensure that
# 1. indentation caused by the "function wrapper()" doesn't apply to the plugin code body
# 2. the wrapper is formatted correctly for removal by the IITC Mobile android app
pluginWrapperStart = """
-function wrapper() {
+function wrapper(plugin_info) {
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};
+//PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!!
+//(leaving them in place might break the 'About IITC' page or break update checks)
+plugin_info.buildName = '@@BUILDNAME@@';
+plugin_info.dateTimeVersion = '@@DATETIMEVERSION@@';
+plugin_info.pluginId = '@@PLUGINNAME@@';
+//END PLUGIN AUTHORS NOTE
+
"""
+
pluginWrapperEnd = """
-if(window.iitcLoaded && typeof setup === 'function') {
- setup();
-} else {
- if(window.bootPlugins)
- window.bootPlugins.push(setup);
- else
- window.bootPlugins = [setup];
-}
+setup.info = plugin_info; //add the script info data to the function as a property
+if(!window.bootPlugins) window.bootPlugins = [];
+window.bootPlugins.push(setup);
+// if IITC has already booted, immediately run the 'setup' function
+if(window.iitcLoaded && typeof setup === 'function') setup();
} // wrapper end
// inject code into site context
var script = document.createElement('script');
-script.appendChild(document.createTextNode('('+ wrapper +')();'));
+var info = {};
+if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description };
+script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');'));
(document.body || document.head || document.documentElement).appendChild(script);
"""
@@ -141,10 +150,13 @@ def extractUserScriptMeta(var):
-def doReplacements(script,updateUrl,downloadUrl):
+def doReplacements(script,updateUrl,downloadUrl,pluginName=None):
script = re.sub('@@INJECTCODE@@',loadCode,script)
+ script = script.replace('@@PLUGINSTART@@', pluginWrapperStart)
+ script = script.replace('@@PLUGINEND@@', pluginWrapperEnd)
+
script = re.sub('@@INCLUDERAW:([0-9a-zA-Z_./-]+)@@', loaderRaw, script)
script = re.sub('@@INCLUDESTRING:([0-9a-zA-Z_./-]+)@@', loaderString, script)
script = re.sub('@@INCLUDEMD:([0-9a-zA-Z_./-]+)@@', loaderMD, script)
@@ -164,8 +176,8 @@ def doReplacements(script,updateUrl,downloadUrl):
script = script.replace('@@UPDATEURL@@', updateUrl)
script = script.replace('@@DOWNLOADURL@@', downloadUrl)
- script = script.replace('@@PLUGINSTART@@', pluginWrapperStart)
- script = script.replace('@@PLUGINEND@@', pluginWrapperEnd)
+ if (pluginName):
+ script = script.replace('@@PLUGINNAME@@', pluginName);
return script
@@ -221,7 +233,8 @@ for fn in glob.glob("plugins/*.user.js"):
downloadUrl = distUrlBase and distUrlBase + '/' + fn.replace("\\","/") or 'none'
updateUrl = distUrlBase and downloadUrl.replace('.user.js', '.meta.js') or 'none'
- script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl)
+ pluginName = os.path.splitext(os.path.splitext(os.path.basename(fn))[0])[0]
+ script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl, pluginName=pluginName)
metafn = fn.replace('.user.js', '.meta.js')
saveScriptAndMeta(script, os.path.join(outDir,fn), os.path.join(outDir,metafn))
@@ -236,7 +249,7 @@ if buildMobile:
script = readfile("mobile/plugins/" + fn)
downloadUrl = distUrlBase and distUrlBase + '/' + fn.replace("\\","/") or 'none'
updateUrl = distUrlBase and downloadUrl.replace('.user.js', '.meta.js') or 'none'
- script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl)
+ script = doReplacements(script, downloadUrl=downloadUrl, updateUrl=updateUrl, pluginName='user-location')
metafn = fn.replace('.user.js', '.meta.js')
saveScriptAndMeta(script, os.path.join(outDir,fn), os.path.join(outDir,metafn))
@@ -263,7 +276,7 @@ if buildMobile:
if buildMobile != 'copyonly':
# now launch 'ant' to build the mobile project
- retcode = os.system("ant %s -buildfile mobile/build.xml %s" % (antOptions, buildMobile))
+ retcode = os.system("ant %s -buildfile %s %s" % (antOptions, antBuildFile, buildMobile))
if retcode != 0:
print ("Error: mobile app failed to build. ant returned %d" % retcode)
diff --git a/code/chat.js b/code/chat.js
index ad1032ce..fc88c670 100644
--- a/code/chat.js
+++ b/code/chat.js
@@ -540,7 +540,6 @@ window.chat.show = function(name) {
? $('#updatestatus').hide()
: $('#updatestatus').show();
$('#chat, #chatinput').show();
- $('#map').css('visibility', 'hidden');
var t = $(''+name+'');
window.chat.chooseAnchor(t);
@@ -681,7 +680,18 @@ window.chat.postMsg = function() {
var msg = $.trim($('#chatinput input').val());
if(!msg || msg === '') return;
- if(c === 'debug') return new Function (msg)();
+ if(c === 'debug') {
+ var result;
+ try {
+ result = eval(msg);
+ } catch(e) {
+ if(e.stack) console.error(e.stack);
+ throw e; // to trigger native error message
+ }
+ if(result !== undefined)
+ console.log(result.toString());
+ return result;
+ }
var publik = c === 'public';
var latlng = map.getCenter();
diff --git a/code/debugging.js b/code/debugging.js
index 14663184..c72b3163 100644
--- a/code/debugging.js
+++ b/code/debugging.js
@@ -23,10 +23,6 @@ window.debug.console = function() {
}
window.debug.console.show = function() {
- if (window.isSmartphone()) {
- $('#scrollwrapper, #updatestatus').hide();
- $('#map').css('visibility', 'hidden');
- }
$('#chat, #chatinput').show();
window.debug.console.create();
$('#chatinput mark').css('cssText', 'color: #bbb !important').text('debug:');
@@ -88,10 +84,20 @@ window.debug.console.error = function(text) {
window.debug.console.overwriteNative = function() {
window.debug.console.create();
- window.console = function() {}
- window.console.log = window.debug.console.log;
- window.console.warn = window.debug.console.warn;
- window.console.error = window.debug.console.error;
+
+ var nativeConsole = window.console;
+ window.console = {};
+
+ function overwrite(which) {
+ window.console[which] = function() {
+ nativeConsole[which].apply(nativeConsole, arguments);
+ window.debug.console[which].apply(window.debug.console, arguments);
+ }
+ }
+
+ overwrite("log");
+ overwrite("warn");
+ overwrite("error");
}
window.debug.console.overwriteNativeIfRequired = function() {
diff --git a/code/geosearch.js b/code/geosearch.js
index ab67a56c..8735cb52 100644
--- a/code/geosearch.js
+++ b/code/geosearch.js
@@ -14,6 +14,7 @@ window.setupGeosearch = function() {
$('#geosearchwrapper img').click(function(){
map.locate({setView : true, maxZoom: 13});
});
+ $('#geosearch').keyup(function(){$(this).removeClass('search_not_found')});
}
window.search = function(search) {
@@ -22,13 +23,16 @@ window.search = function(search) {
}
$.getJSON(NOMINATIM + encodeURIComponent(search), function(data) {
- if(!data || !data[0]) return true;
+ if(!data || !data[0]) {
+ $('#geosearch').addClass('search_not_found');
+ return true;
+ }
var b = data[0].boundingbox;
if(!b) return true;
var southWest = new L.LatLng(b[0], b[2]),
northEast = new L.LatLng(b[1], b[3]),
bounds = new L.LatLngBounds(southWest, northEast);
window.map.fitBounds(bounds);
- if(window.isSmartphone()) window.smartphone.mapButton.click();
+ if(window.isSmartphone()) window.show('map');
});
}
diff --git a/code/hooks.js b/code/hooks.js
index f415fe62..b6a7ef6c 100644
--- a/code/hooks.js
+++ b/code/hooks.js
@@ -15,6 +15,9 @@
// required to successfully boot the plugin.
//
// Here’s more specific information about each event:
+// playerNameResolved: called when unresolved player name get resolved.
+// Argument is {names: object} which names[guid] is the
+// resolved player name.
// portalSelected: called when portal on map is selected/unselected.
// Provide guid of selected and unselected portal.
// mapDataRefreshStart: called when we start refreshing map data
@@ -49,7 +52,7 @@
window._hooks = {}
window.VALID_HOOKS = [
- 'portalSelected',
+ 'playerNameResolved', 'portalSelected',
'mapDataRefreshStart', 'mapDataRefreshEnd',
'portalAdded', 'linkAdded', 'fieldAdded',
'portalDetailsUpdated',
diff --git a/code/map_data_cache.js b/code/map_data_cache.js
index c143e9c9..a04070fc 100644
--- a/code/map_data_cache.js
+++ b/code/map_data_cache.js
@@ -2,8 +2,16 @@
// cache for map data tiles.
window.DataCache = function() {
- this.REQUEST_CACHE_FRESH_AGE = 60; // if younger than this, use data in the cache rather than fetching from the server
- this.REQUEST_CACHE_MAX_AGE = 180; // maximum cache age. entries are deleted from the cache after this time
+ // stock site nemesis.dashboard.DataManager.CACHE_EXPIRY_MS_ = 18E4 - so should be 2 mins cache time
+ this.REQUEST_CACHE_FRESH_AGE = 120; // if younger than this, use data in the cache rather than fetching from the server
+
+ // stale cache entries can be updated (that's what the optional 'timestampMs' field in getThinnedEntnties is
+ // for, retrieving deltas) so use a long max age to take advantage of this
+ // however, ther must be an overall limit on the maximum age of data from the servers, otherwise the deletedEntity
+ // entries would grow indefinitely. an hour seems reasonable from experience with the data, so 55 mins max cache time
+// this.REQUEST_CACHE_MAX_AGE = 55*60; // maximum cache age. entries are deleted from the cache after this time
+//UPDATE: this timestampMs parameter doesn't work, so reduced max age to limit RAM usage
+ this.REQUEST_CACHE_MAX_AGE = 15*60; // maximum cache age. entries are deleted from the cache after this time
if (L.Browser.mobile) {
// on mobile devices, smaller cache size
@@ -18,15 +26,19 @@ window.DataCache = function() {
}
-window.DataCache.prototype.store = function(qk,data,date) {
+window.DataCache.prototype.store = function(qk,data,freshTime) {
// fixme? common behaviour for objects is that properties are kept in the order they're added
// this is handy, as it allows easy retrieval of the oldest entries for expiring
// however, this is not guaranteed by the standards, but all our supported browsers work this way
delete this._cache[qk];
- if (date === undefined) date = new Date();
- this._cache[qk] = { time: date.getTime(), data: data };
+ var time = new Date().getTime();
+
+ if (freshTime===undefined) freshTime = this.REQUEST_CACHE_FRESH_AGE*1000;
+ var expire = time + freshTime;
+
+ this._cache[qk] = { time: time, expire: expire, data: data };
}
window.DataCache.prototype.get = function(qk) {
@@ -42,8 +54,8 @@ window.DataCache.prototype.getTime = function(qk) {
window.DataCache.prototype.isFresh = function(qk) {
if (qk in this._cache) {
var d = new Date();
- var t = d.getTime() - this.REQUEST_CACHE_FRESH_AGE*1000;
- if (this._cache[qk].time >= t) return true;
+ var t = d.getTime();
+ if (this._cache[qk].expire >= t) return true;
else return false;
}
diff --git a/code/map_data_calc_tools.js b/code/map_data_calc_tools.js
index 8f845c5e..884acc40 100644
--- a/code/map_data_calc_tools.js
+++ b/code/map_data_calc_tools.js
@@ -9,26 +9,33 @@
// Convertion functions courtesy of
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
-window.lngToTile = function(lng, zoom) {
- return Math.floor((lng + 180) / 360 * Math.pow(2, (zoom>12)?zoom:(zoom+2)));
+
+window.levelToTilesPerEdge = function(level) {
+ var LEVEL_TO_TILES_PER_EDGE = [65536, 65536, 16384, 16384, 4096, 1536, 1024, 256, 32];
+ return LEVEL_TO_TILES_PER_EDGE[level];
}
-window.latToTile = function(lat, zoom) {
+
+window.lngToTile = function(lng, level) {
+ return Math.floor((lng + 180) / 360 * levelToTilesPerEdge(level));
+}
+
+window.latToTile = function(lat, level) {
return Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, (zoom>12)?zoom:(zoom+2)));
+ 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * levelToTilesPerEdge(level));
}
-window.tileToLng = function(x, zoom) {
- return x / Math.pow(2, (zoom>12)?zoom:(zoom+2)) * 360 - 180;
+window.tileToLng = function(x, level) {
+ return x / levelToTilesPerEdge(level) * 360 - 180;
}
-window.tileToLat = function(y, zoom) {
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, (zoom>12)?zoom:(zoom+2));
+window.tileToLat = function(y, level) {
+ var n = Math.PI - 2 * Math.PI * y / levelToTilesPerEdge(level);
return 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
}
-window.pointToTileId = function(zoom, x, y) {
- return zoom + "_" + x + "_" + y;
+window.pointToTileId = function(level, x, y) {
+ return level + "_" + x + "_" + y;
}
// given tile id and bounds, returns the format as required by the
diff --git a/code/map_data_render.js b/code/map_data_render.js
index ec06f4e0..85b89b9c 100644
--- a/code/map_data_render.js
+++ b/code/map_data_render.js
@@ -192,7 +192,9 @@ window.Render.prototype.deletePortalEntity = function(guid) {
window.Render.prototype.deleteLinkEntity = function(guid) {
if (guid in window.links) {
var l = window.links[guid];
- linksFactionLayers[l.options.team].removeLayer(l);
+ if (linksFactionLayers[l.options.team].hasLayer(l)) {
+ linksFactionLayers[l.options.team].removeLayer(l);
+ }
delete window.links[guid];
}
}
diff --git a/code/map_data_request.js b/code/map_data_request.js
index e6fcb799..ae53421e 100644
--- a/code/map_data_request.js
+++ b/code/map_data_request.js
@@ -28,24 +28,27 @@ window.MapDataRequest = function() {
this.MAX_TILE_RETRIES = 3;
// refresh timers
- this.MOVE_REFRESH = 0.5; //refresh time to use after a move
- this.STARTUP_REFRESH = 5; //refresh time used on first load of IITC
+ this.MOVE_REFRESH = 1; //time, after a map move (pan/zoom) before starting the refresh processing
+ this.STARTUP_REFRESH = 3; //refresh time used on first load of IITC
this.IDLE_RESUME_REFRESH = 5; //refresh time used after resuming from idle
// after one of the above, there's an additional delay between preparing the refresh (clearing out of bounds,
// processing cache, etc) and actually sending the first network requests
this.DOWNLOAD_DELAY = 3; //delay after preparing the data download before tile requests are sent
- // a short delay between one request finishing and the queue being run for the next request
+
+ // a short delay between one request finishing and the queue being run for the next request.
+ // this gives a chance of other requests finishing, allowing better grouping of retries in new requests
this.RUN_QUEUE_DELAY = 0.5;
- // delay before re-queueing tiles
- this.TILE_TIMEOUT_REQUEUE_DELAY = 0.5; // short delay before retrying a 'error==TIMEOUT' tile - as this is very common
- this.BAD_REQUEST_REQUEUE_DELAY = 4; // longer delay before retrying a completely failed request - as in this case the servers are struggling
+ // delay before re-queueing tiles in failed requests
+ this.BAD_REQUEST_REQUEUE_DELAY = 5; // longer delay before retrying a completely failed request - as in this case the servers are struggling
+
+ // a delay before processing the queue after requeueing tiles. this gives a chance for other requests to finish
+ // or other requeue actions to happen before the queue is processed, allowing better grouping of requests
+ // however, the queue may be processed sooner if a previous timeout was set
+ this.REQUEUE_DELAY = 1;
- // additionally, a delay before processing the queue after requeueing tiles
- // (this way, if multiple requeue delays finish within a short time of each other, they're all processed in one queue run)
- this.RERUN_QUEUE_DELAY = 2;
this.REFRESH_CLOSE = 120; // refresh time to use for close views z>12 when not idle and not moving
this.REFRESH_FAR = 600; // refresh time for far views z <= 12
@@ -89,8 +92,8 @@ window.MapDataRequest.prototype.mapMoveEnd = function() {
if (this.fetchedDataParams) {
// we have fetched (or are fetching) data...
- if (this.fetchedDataParams.zoom == zoom && this.fetchedDataParams.bounds.contains(bounds)) {
- // ... and the data zoom levels are the same, and the current bounds is inside the fetched bounds
+ if (this.fetchedDataParams.mapZoom == map.getZoom() && this.fetchedDataParams.bounds.contains(bounds)) {
+ // ... and the zoom level is the same and the current bounds is inside the fetched bounds
// so, no need to fetch data. if there's time left, restore the original timeout
var remainingTime = (this.timerExpectedTimeoutTime - new Date().getTime())/1000;
@@ -169,8 +172,8 @@ window.MapDataRequest.prototype.refresh = function() {
// a 'set' to keep track of hard failures for tiles
this.tileErrorCount = {};
- // fill tileBounds with the data needed to request each tile
- this.tileBounds = {};
+ // the 'set' of requested tile QKs
+ this.queuedTiles = {};
var bounds = clampLatLngBounds(map.getBounds());
@@ -183,24 +186,24 @@ window.MapDataRequest.prototype.refresh = function() {
//var debugrect = L.rectangle(bounds,{color: 'red', fill: false, weight: 4, opacity: 0.8}).addTo(map);
//setTimeout (function(){ map.removeLayer(debugrect); }, 10*1000);
- var x1 = lngToTile(bounds.getWest(), zoom);
- var x2 = lngToTile(bounds.getEast(), zoom);
- var y1 = latToTile(bounds.getNorth(), zoom);
- var y2 = latToTile(bounds.getSouth(), zoom);
+ var x1 = lngToTile(bounds.getWest(), minPortalLevel);
+ var x2 = lngToTile(bounds.getEast(), minPortalLevel);
+ var y1 = latToTile(bounds.getNorth(), minPortalLevel);
+ var y2 = latToTile(bounds.getSouth(), minPortalLevel);
// calculate the full bounds for the data - including the part of the tiles off the screen edge
var dataBounds = L.latLngBounds([
- [tileToLat(y2+1,zoom), tileToLng(x1,zoom)],
- [tileToLat(y1,zoom), tileToLng(x2+1,zoom)]
+ [tileToLat(y2+1,minPortalLevel), tileToLng(x1,minPortalLevel)],
+ [tileToLat(y1,minPortalLevel), tileToLng(x2+1,minPortalLevel)]
]);
//var debugrect2 = L.rectangle(dataBounds,{color: 'magenta', fill: false, weight: 4, opacity: 0.8}).addTo(map);
//setTimeout (function(){ map.removeLayer(debugrect2); }, 10*1000);
// store the parameters used for fetching the data. used to prevent unneeded refreshes after move/zoom
- this.fetchedDataParams = { bounds: dataBounds, zoom: zoom };
+ this.fetchedDataParams = { bounds: dataBounds, mapZoom: map.getZoom(), minPortalLevel: minPortalLevel };
- window.runHooks ('mapDataRefreshStart', {bounds: bounds, zoom: zoom, tileBounds: dataBounds});
+ window.runHooks ('mapDataRefreshStart', {bounds: bounds, zoom: zoom, minPortalLevel: minPortalLevel, tileBounds: dataBounds});
this.render.startRenderPass();
this.render.clearPortalsBelowLevel(minPortalLevel);
@@ -224,11 +227,11 @@ window.MapDataRequest.prototype.refresh = function() {
for (var y = y1; y <= y2; y++) {
// x goes from bottom to top(?)
for (var x = x1; x <= x2; x++) {
- var tile_id = pointToTileId(zoom, x, y);
- var latNorth = tileToLat(y,zoom);
- var latSouth = tileToLat(y+1,zoom);
- var lngWest = tileToLng(x,zoom);
- var lngEast = tileToLng(x+1,zoom);
+ var tile_id = pointToTileId(minPortalLevel, x, y);
+ var latNorth = tileToLat(y,minPortalLevel);
+ var latSouth = tileToLat(y+1,minPortalLevel);
+ var lngWest = tileToLng(x,minPortalLevel);
+ var lngEast = tileToLng(x+1,minPortalLevel);
this.debugTiles.create(tile_id,[[latSouth,lngWest],[latNorth,lngEast]]);
@@ -238,16 +241,17 @@ window.MapDataRequest.prototype.refresh = function() {
this.render.processTileData (this.cache.get(tile_id));
this.cachedTileCount += 1;
} else {
- // no fresh data - queue a request
- var boundsParams = generateBoundsParams(
- tile_id,
- latSouth,
- lngWest,
- latNorth,
- lngEast
- );
- this.tileBounds[tile_id] = boundsParams;
+ // no fresh data
+
+ // render the cached stale data, if we have it. this ensures *something* appears quickly when possible
+ var old_data = this.cache && this.cache.get(tile_id);
+ if (old_data) {
+ this.render.processTileData (old_data);
+ }
+
+ // queue a request
+ this.queuedTiles[tile_id] = tile_id;
this.requestedTileCount += 1;
}
}
@@ -255,10 +259,19 @@ window.MapDataRequest.prototype.refresh = function() {
this.setStatus ('loading');
+ // technically a request hasn't actually finished - however, displayed portal data has been refreshed
+ // so as far as plugins are concerned, it should be treated as a finished request
+ window.runHooks('requestFinished', {success: true});
+
console.log ('done request preperation (cleared out-of-bounds and invalid for zoom, and rendered cached data)');
- // don't start processing the download queue immediately - start it after a short delay
- this.delayProcessRequestQueue (this.DOWNLOAD_DELAY,true);
+ if (Object.keys(this.queuedTiles).length > 0) {
+ // queued requests - don't start processing the download queue immediately - start it after a short delay
+ this.delayProcessRequestQueue (this.DOWNLOAD_DELAY,true);
+ } else {
+ // all data was from the cache, nothing queued - run the queue 'immediately' so it handles the end request processing
+ this.delayProcessRequestQueue (0,true);
+ }
}
@@ -273,7 +286,7 @@ window.MapDataRequest.prototype.delayProcessRequestQueue = function(seconds,isFi
window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) {
// if nothing left in the queue, end the render. otherwise, send network requests
- if (Object.keys(this.tileBounds).length == 0) {
+ if (Object.keys(this.queuedTiles).length == 0) {
this.render.endRenderPass();
@@ -301,7 +314,7 @@ window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) {
// create a list of tiles that aren't requested over the network
var pendingTiles = [];
- for (var id in this.tileBounds) {
+ for (var id in this.queuedTiles) {
if (!(id in this.requestedTiles) ) {
pendingTiles.push(id);
}
@@ -351,7 +364,7 @@ window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) {
window.MapDataRequest.prototype.sendTileRequest = function(tiles) {
- var boundsParamsList = [];
+ var tilesList = [];
for (var i in tiles) {
var id = tiles[i];
@@ -360,15 +373,14 @@ window.MapDataRequest.prototype.sendTileRequest = function(tiles) {
this.requestedTiles[id] = true;
- var boundsParams = this.tileBounds[id];
- if (boundsParams) {
- boundsParamsList.push (boundsParams);
+ if (id in this.queuedTiles) {
+ tilesList.push (id);
} else {
- console.warn('failed to find bounds for tile id '+id);
+ console.warn('no queue entry for tile id '+id);
}
}
- var data = { boundsParamsList: boundsParamsList };
+ var data = { quadKeys: tilesList };
this.activeRequestCount += 1;
@@ -382,7 +394,7 @@ window.MapDataRequest.prototype.sendTileRequest = function(tiles) {
}
window.MapDataRequest.prototype.requeueTile = function(id, error) {
- if (id in this.tileBounds) {
+ if (id in this.queuedTiles) {
// tile is currently wanted...
// first, see if the error can be ignored due to retry counts
@@ -408,7 +420,7 @@ window.MapDataRequest.prototype.requeueTile = function(id, error) {
this.failedTileCount += 1;
}
// and delete from the pending requests...
- delete this.tileBounds[id];
+ delete this.queuedTiles[id];
} else {
// if false, was a 'timeout' or we're retrying, so unlimited retries (as the stock site does)
@@ -418,9 +430,8 @@ window.MapDataRequest.prototype.requeueTile = function(id, error) {
// proper queue, just an object with guid as properties. Javascript standards don't guarantee the order of properties
// within an object. however, all current browsers do keep property order, and new properties are added at the end.
// therefore, delete and re-add the requeued tile and it will be added to the end of the queue
- var boundsData = this.tileBounds[id];
- delete this.tileBounds[id];
- this.tileBounds[id] = boundsData;
+ delete this.queuedTiles[id];
+ this.queuedTiles[id] = id;
}
} // else the tile wasn't currently wanted (an old non-cancelled request) - ignore
@@ -463,7 +474,6 @@ window.MapDataRequest.prototype.handleResponse = function (data, tiles, success)
if (val.error == "TIMEOUT") {
// TIMEOUT errors for individual tiles are 'expected'(!) - and result in a silent unlimited retries
timeoutTiles.push (id);
- this.debugTiles.setState (id, 'tile-timeout');
} else {
console.warn('map data tile '+id+' failed: error=='+val.error);
errorTiles.push (id);
@@ -478,12 +488,12 @@ window.MapDataRequest.prototype.handleResponse = function (data, tiles, success)
// if this tile was in the render list, render it
// (requests aren't aborted when new requests are started, so it's entirely possible we don't want to render it!)
- if (id in this.tileBounds) {
+ if (id in this.queuedTiles) {
this.debugTiles.setState (id, 'ok');
this.render.processTileData (val);
- delete this.tileBounds[id];
+ delete this.queuedTiles[id];
this.successTileCount += 1;
} // else we don't want this tile (from an old non-cancelled request) - ignore
@@ -491,6 +501,9 @@ window.MapDataRequest.prototype.handleResponse = function (data, tiles, success)
}
+ // TODO? check for any requested tiles in 'tiles' not being mentioned in the response - and handle as if it's a 'timeout'?
+
+
window.runHooks('requestFinished', {success: true});
}
@@ -498,28 +511,27 @@ window.MapDataRequest.prototype.handleResponse = function (data, tiles, success)
console.log ('getThinnedEntities status: '+tiles.length+' tiles: '+successTiles.length+' successful, '+timeoutTiles.length+' timed out, '+errorTiles.length+' failed');
- //setTimeout has no way of passing the 'context' (aka 'this') to it's function
- var savedContext = this;
-
+ // requeue any 'timeout' tiles immediately
if (timeoutTiles.length > 0) {
- setTimeout (function() {
- for (var i in timeoutTiles) {
- var id = timeoutTiles[i];
- delete savedContext.requestedTiles[id];
- savedContext.requeueTile(id, false);
- }
- savedContext.delayProcessRequestQueue(this.RERUN_QUEUE_DELAY);
- }, this.TILE_TIMEOUT_REQUEUE_DELAY*1000);
+ for (var i in timeoutTiles) {
+ var id = timeoutTiles[i];
+ delete this.requestedTiles[id];
+ this.requeueTile(id, false);
+ }
}
+ // but for other errors, delay before retrying (as the server is having issues)
if (errorTiles.length > 0) {
+ //setTimeout has no way of passing the 'context' (aka 'this') to it's function
+ var savedContext = this;
+
setTimeout (function() {
for (var i in errorTiles) {
var id = errorTiles[i];
delete savedContext.requestedTiles[id];
savedContext.requeueTile(id, true);
}
- savedContext.delayProcessRequestQueue(this.RERUN_QUEUE_DELAY);
+ savedContext.delayProcessRequestQueue(this.REQUEUE_DELAY);
}, this.BAD_REQUEST_REQUEUE_DELAY*1000);
}
diff --git a/code/panes.js b/code/panes.js
index 8ab4610e..4c3898d4 100644
--- a/code/panes.js
+++ b/code/panes.js
@@ -1,42 +1,45 @@
// created to start cleaning up "window" interaction
//
window.show = function(id) {
- window.hideall();
- if (typeof android !== 'undefined' && android && android.switchToPane) {
- android.switchToPane(id);
- }
- switch(id) {
- case 'full':
- window.chat.show('full');
- break;
- case 'compact':
- window.chat.show('compact');
- break;
- case 'public':
- window.chat.show('public');
- break;
- case 'faction':
- window.chat.show('faction');
- break;
- case 'debug':
- window.debug.console.show();
- break;
- case 'map':
- window.smartphone.mapButton.click();
- $('#portal_highlight_select').show();
- $('#farm_level_select').show();
- break;
- case 'info':
- window.smartphone.sideButton.click();
- break;
- default:
- window.smartphone.mapButton.click();
- break;
- }
+ window.hideall();
+
+ switch(id) {
+ case 'full':
+ window.chat.show('full');
+ break;
+ case 'compact':
+ window.chat.show('compact');
+ break;
+ case 'public':
+ window.chat.show('public');
+ break;
+ case 'faction':
+ window.chat.show('faction');
+ break;
+ case 'debug':
+ window.debug.console.show();
+ break;
+ case 'map':
+ window.smartphone.mapButton.click();
+ $('#portal_highlight_select').show();
+ $('#farm_level_select').show();
+ break;
+ case 'info':
+ window.smartphone.sideButton.click();
+ break;
+ default:
+ window.smartphone.mapButton.click();
+ break;
+ }
+
+ if (typeof android !== 'undefined' && android && android.switchToPane) {
+ android.switchToPane(id);
+ }
}
window.hideall = function() {
- $('#chatcontrols, #chat, #chatinput, #sidebartoggle, #scrollwrapper, #updatestatus, #portal_highlight_select').hide();
- $('#farm_level_select').hide();
- $('#map').css('visibility', 'hidden');
+ $('#chatcontrols, #chat, #chatinput, #sidebartoggle, #scrollwrapper, #updatestatus, #portal_highlight_select').hide();
+ $('#farm_level_select').hide();
+ $('#map').css('visibility', 'hidden');
+ $('.ui-tooltip').remove();
}
diff --git a/code/player_names.js b/code/player_names.js
index e79cf874..7914c706 100644
--- a/code/player_names.js
+++ b/code/player_names.js
@@ -39,6 +39,12 @@ window.playerNameToGuid = function(playerName) {
var cachedGuid = window._playerNameToGuidCache[playerName];
if (cachedGuid !== undefined) return cachedGuid;
+ // IITC needs our own player GUID, from a lookup by name. so we retrieve this from localstorage (if available)
+ if (playerName == PLAYER.nickname) {
+ cachedGuid = localStorage['PLAYER-'+PLAYER.nickname];
+ if (cachedGuid !== undefined) return cachedGuid;
+ }
+
var guid = null;
$.each(Object.keys(sessionStorage), function(ind,key) {
if(playerName === sessionStorage[key]) {
@@ -68,9 +74,11 @@ window.resolvePlayerNames = function() {
window.playersInResolving = window.playersInResolving.concat(p);
postAjax('getPlayersByGuids', d, function(dat) {
+ var resolvedName = {};
if(dat.result) {
$.each(dat.result, function(ind, player) {
window.setPlayerName(player.guid, player.nickname);
+ resolvedName[player.guid] = player.nickname;
// remove from array
window.playersInResolving.splice(window.playersInResolving.indexOf(player.guid), 1);
});
@@ -82,6 +90,9 @@ window.resolvePlayerNames = function() {
//therefore, not a good idea to automatically retry by adding back to the playersToResolve list
}
+ // Run hook 'playerNameResolved' with the resolved player names
+ window.runHooks('playerNameResolved', {names: resolvedName});
+
//TODO: have an event triggered for this instead of hard-coded single function call
if(window.selectedPortal)
window.renderPortalDetails(window.selectedPortal);
@@ -107,22 +118,17 @@ window.setPlayerName = function(guid, nick, uncertain) {
alert('You have run into bug #37. Please help me solve it!\nCopy and paste this text and post it here:\nhttps://github.com/breunigs/ingress-intel-total-conversion/issues/37\nIf copy & pasting doesn’t work, make a screenshot instead.\n\n\n' + window.debug.printStackTrace() + '\n\n\n' + JSON.stringify(nick));
}
sessionStorage[guid] = nick;
+
+ // IITC needs our own player ID early on in startup. the only way we can find this is by something else
+ // doing a guid->name lookup for our own name. as this doesn't always happen - and likely won't happen when needed
+ // we'll store our own name->guid lookup in localStorage
+ if (nick == PLAYER.nickname) {
+ localStorage['PLAYER-'+PLAYER.nickname] = guid;
+ PLAYER.guid = guid; // set it in PLAYER in case it wasn't already done
+ }
}
-window.loadPlayerNamesForPortal = function(portal_details) {
- if(map.getZoom() < PRECACHE_PLAYER_NAMES_ZOOM) return;
- var e = portal_details;
-
- if(e.captured && e.captured.capturingPlayerId)
- getPlayerName(e.captured.capturingPlayerId);
-
- if(!e.resonatorArray || !e.resonatorArray.resonators) return;
-
- $.each(e.resonatorArray.resonators, function(ind, reso) {
- if(reso) getPlayerName(reso.ownerGuid);
- });
-}
// test to see if a specific player GUID is a special system account (e.g. __JARVIS__, __ADA__) that shouldn't
diff --git a/code/portal_detail_display.js b/code/portal_detail_display.js
index 5004ce1c..47967e57 100644
--- a/code/portal_detail_display.js
+++ b/code/portal_detail_display.js
@@ -90,6 +90,17 @@ window.renderPortalDetails = function(guid) {
portalDetailedDescription += '';
}
+ var levelDetails = getPortalLevel(d);
+ if(levelDetails != 8) {
+ if(levelDetails==Math.ceil(levelDetails))
+ levelDetails += "\n8";
+ else
+ levelDetails += "\n" + (Math.ceil(levelDetails) - levelDetails)*8;
+ levelDetails += " resonator level(s) needed for next portal level";
+ } else {
+ levelDetails += "\nfully upgraded";
+ }
+ levelDetails = "Level " + levelDetails;
$('#portaldetails')
.attr('class', TEAM_TO_CSS[getTeam(d)])
@@ -98,7 +109,7 @@ window.renderPortalDetails = function(guid) {
+ 'X'
// help cursor via ".imgpreview img"
+ '
',
- title: name,
- id: 'poslinks'
- });
- }
-}
-
-window.androidCopy = function(text) {
- if(typeof android === 'undefined' || !android || !android.copy)
- return true; // i.e. execute other actions
- else
- android.copy(text);
- return false;
-}
-
-window.androidPermalink = function() {
- if(typeof android === 'undefined' || !android || !android.copy)
- return true; // i.e. execute other actions
-
- var center = map.getCenter();
- android.intentPosLink(center.lat, center.lng, map.getZoom(), "Intel Map", false);
- return false;
-}
-
-
-window.getPortalDataZoom = function() {
- var mapZoom = map.getZoom();
-
- // make sure we're dealing with an integer here
- // (mobile: a float somehow gets through in some cases!)
- var z = parseInt(mapZoom);
-
- // limiting the mazimum zoom level for data retrieval reduces the number of requests at high zoom levels
- // (as all portal data is retrieved at z=17, why retrieve multiple z=18 tiles when fewer z=17 would do?)
- // very effective along with the new cache code
- if (z > 17) z=17;
-
- //sanity check - should never happen
- if (z < 0) z=0;
-
- return z;
-}
-
-
-window.getMinPortalLevelForZoom = function(z) {
-//based on code from stock gen_dashboard.js
- switch(z) {
- case 0:
- case 1:
- case 2:
- case 3:
- return 8;
- case 4:
- case 5:
- return 7;
- case 6:
- case 7:
- return 6;
- case 8:
- return 5;
- case 9:
- case 10:
- return 4;
- case 11:
- case 12:
- return 3;
- case 13:
- case 14:
- return 2;
- case 15:
- case 16:
- return 1;
- default:
- return 0
- }
-}
-
-
-window.getMinPortalLevel = function() {
- var z = getPortalDataZoom();
- return getMinPortalLevelForZoom(z);
-}
-
-// returns number of pixels left to scroll down before reaching the
-// bottom. Works similar to the native scrollTop function.
-window.scrollBottom = function(elm) {
- if(typeof elm === 'string') elm = $(elm);
- return elm.get(0).scrollHeight - elm.innerHeight() - elm.scrollTop();
-}
-
-window.zoomToAndShowPortal = function(guid, latlng) {
- map.setView(latlng, 17);
- // if the data is available, render it immediately. Otherwise defer
- // until it becomes available.
- if(window.portals[guid])
- renderPortalDetails(guid);
- else
- urlPortal = guid;
-}
-
-
-String.prototype.capitalize = function() {
- return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
-}
-
-// http://stackoverflow.com/a/646643/1684530 by Bergi and CMS
-if (typeof String.prototype.startsWith !== 'function') {
- String.prototype.startsWith = function (str){
- return this.slice(0, str.length) === str;
- };
-}
-
-// escape a javascript string, so quotes and backslashes are escaped with a backslash
-// (for strings passed as parameters to html onclick="..." for example)
-window.escapeJavascriptString = function(str) {
- return (str+'').replace(/[\\"']/g,'\\$&');
-}
-
-//escape special characters, such as tags
-window.escapeHtmlSpecialChars = function(str) {
- var div = document.createElement(div);
- var text = document.createTextNode(str);
- div.appendChild(text);
- return div.innerHTML;
-}
-
-window.prettyEnergy = function(nrg) {
- return nrg> 1000 ? Math.round(nrg/1000) + ' k': nrg;
-}
-
-window.setPermaLink = function(elm) {
- var c = map.getCenter();
- var lat = Math.round(c.lat*1E6)/1E6;
- var lng = Math.round(c.lng*1E6)/1E6;
- var qry = 'll='+lat+','+lng+'&z=' + map.getZoom();
- $(elm).attr('href', '/intel?' + qry);
-}
-
-window.uniqueArray = function(arr) {
- return $.grep(arr, function(v, i) {
- return $.inArray(v, arr) === i;
- });
-}
-
-window.genFourColumnTable = function(blocks) {
- var t = $.map(blocks, function(detail, index) {
- if(!detail) return '';
- if(index % 2 === 0)
- return '
'+detail[1]+'
'+detail[0]+'
';
- else
- return '
'+detail[0]+'
'+detail[1]+'
';
- }).join('');
- if(t.length % 2 === 1) t + '
';
- return t;
-}
-
-
-// converts given text with newlines (\n) and tabs (\t) to a HTML
-// table automatically.
-window.convertTextToTableMagic = function(text) {
- // check if it should be converted to a table
- if(!text.match(/\t/)) return text.replace(/\n/g, ' ');
-
- var data = [];
- var columnCount = 0;
-
- // parse data
- var rows = text.split('\n');
- $.each(rows, function(i, row) {
- data[i] = row.split('\t');
- if(data[i].length > columnCount) columnCount = data[i].length;
- });
-
- // build the table
- var table = '
IITC Mobile is an optimized mobile browser for the
Ingress Intel Total Conversion (IITC) userscript by breunigs.
After Niantic asked the main developer to shut down his github project, development
- is continued on a fork of jonatkins.
- Community:
+ is continued on a fork of jonatkins.
+
Community:
• Visit the IITC website for new releases and the desktop version.
• Follow the IITC Google+ page
for release announcements.
• Join the IITC Google+ community
- - a place to ask for help and discuss with other users.
';
+ +'Copy/Export Bookmarks'
+ +'Paste/Import Bookmarks'
+ +'Reset Bookmarks'
+ +'Share all Bookmarks (IITCm)'
+ +'Save box position (No IITCm)'
+ +'Reset box position (No IITCm)'
+ +'';
}
/***************************************************************************************************************************************************************/
var setup = function() {
-
window.plugin.bookmarks.isSmart = window.isSmartphone();
// Fired when a bookmarks/folder is removed, added or sorted, also when a folder is opened/closed.
if($.inArray('pluginBkmrksEdit', window.VALID_HOOKS) < 0) { window.VALID_HOOKS.push('pluginBkmrksEdit'); }
// Fired when the "Bookmarks Options" panell is opened (you can add new options);
if($.inArray('pluginBkmrksOpenOpt', window.VALID_HOOKS) < 0) { window.VALID_HOOKS.push('pluginBkmrksOpenOpt'); }
+ // Fired when the sync is finished;
+ if($.inArray('pluginBkmrksSyncEnd', window.VALID_HOOKS) < 0) { window.VALID_HOOKS.push('pluginBkmrksSyncEnd'); }
// If the storage not exists or is a old version
window.plugin.bookmarks.createStorage();
@@ -849,23 +944,6 @@
$('.bkmrksStar').remove();
}
});
-
- // in the future i hope in a 'portalClosed' hook
- /* hook done
- window.unselectOldPortal = function() {
- var oldPortal = portals[selectedPortal];
- if(oldPortal) portalResetColor(oldPortal);
- selectedPortal = null;
- $('#portaldetails').html('');
- if(isSmartphone()) {
- $('.fullimg').remove();
- $('#mobileinfo').html('');
- }
- clearPortalIndicators();
- $('.bkmrksStar').remove();
- }
- */
-
}
$('#toolbox').append(window.plugin.bookmarks.htmlCallSetBox+window.plugin.bookmarks.htmlCalldrawBox);
@@ -877,10 +955,24 @@
if(window.plugin.bookmarks.statusBox['page'] === 1) { $('#bookmarksBox h5.bkmrk_portals').trigger('click'); }
window.addHook('portalDetailsUpdated', window.plugin.bookmarks.addStarToSidebar);
+
+ // Sync
window.addHook('pluginBkmrksEdit', window.plugin.bookmarks.syncBkmrks);
window.addHook('iitcLoaded', window.plugin.bookmarks.registerFieldForSyncing);
+
+ // Highlighter - bookmarked portals
+ window.addHook('pluginBkmrksEdit', window.plugin.bookmarks.highlightRefresh);
+ window.addHook('pluginBkmrksSyncEnd', window.plugin.bookmarks.highlightRefresh);
+ window.addPortalHighlighter('Bookmarked Portals', window.plugin.bookmarks.highlight);
+
+ // Layer - Bookmarked portals
+ window.plugin.bookmarks.starLayerGroup = new L.LayerGroup();
+ window.addLayerGroup('Bookmarked Portals', window.plugin.bookmarks.starLayerGroup, false);
+ window.plugin.bookmarks.addAllStars();
+ window.addHook('pluginBkmrksEdit', window.plugin.bookmarks.editStar);
+ window.addHook('pluginBkmrksSyncEnd', window.plugin.bookmarks.resetAllStars);
}
// PLUGIN END //////////////////////////////////////////////////////////
-@@PLUGINEND@@
+@@PLUGINEND@@
\ No newline at end of file
diff --git a/plugins/bookmarks-css.css b/plugins/bookmarks-css.css
index fa4667ac..2fca0d09 100644
--- a/plugins/bookmarks-css.css
+++ b/plugins/bookmarks-css.css
@@ -223,7 +223,7 @@
display:none;
position:absolute;
top:0;
- left:250px;
+ left:277px;
width:47px;
margin-top:-36px;
height:64px;
@@ -243,7 +243,8 @@
width:auto;
}
#bkmrksTrigger, .bkmrksStar span{
- background-image:url(@@INCLUDEIMAGE:plugins/bookmarks-img.png@@);}
+ background-image:url(@@INCLUDEIMAGE:plugins/bookmarks-img.png@@);
+}
.bkmrksStar span{
display:inline-block;
float:left;
diff --git a/plugins/draw-tools.user.js b/plugins/draw-tools.user.js
index 335825f3..ef28b8f8 100644
--- a/plugins/draw-tools.user.js
+++ b/plugins/draw-tools.user.js
@@ -2,7 +2,7 @@
// @id iitc-plugin-draw-tools@breunigs
// @name IITC plugin: draw tools
// @category Layer
-// @version 0.5.1.@@DATETIMEVERSION@@
+// @version 0.5.3.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@@ -197,7 +197,7 @@ window.plugin.drawTools.load = function() {
layer = L.geodesicPolygon(item.latLngs,window.plugin.drawTools.polygonOptions);
break;
case 'circle':
- layer = L.circle(item.latLng,item.radius,window.plugin.drawTools.polygonOptions);
+ layer = L.geodesicCircle(item.latLng,item.radius,window.plugin.drawTools.polygonOptions);
break;
case 'marker':
layer = L.marker(item.latLng,window.plugin.drawTools.markerOptions)
diff --git a/plugins/player-tracker.user.js b/plugins/player-tracker.user.js
index 07520a1a..f79e382a 100644
--- a/plugins/player-tracker.user.js
+++ b/plugins/player-tracker.user.js
@@ -19,7 +19,7 @@
// PLUGIN START ////////////////////////////////////////////////////////
window.PLAYER_TRACKER_MAX_TIME = 3*60*60*1000; // in milliseconds
window.PLAYER_TRACKER_MIN_ZOOM = 9;
-
+window.PLAYER_TRACKER_MIN_OPACITY = 0.3;
window.PLAYER_TRACKER_LINE_COLOUR = '#FF00FD';
@@ -45,11 +45,18 @@ window.plugin.playerTracker.setup = function() {
iconRetinaUrl: iconResRetImage
}});
- plugin.playerTracker.drawnTraces = new L.LayerGroup();
- window.addLayerGroup('Player Tracker', plugin.playerTracker.drawnTraces, true);
+ plugin.playerTracker.drawnTracesEnl = new L.LayerGroup();
+ plugin.playerTracker.drawnTracesRes = new L.LayerGroup();
+ // to avoid any favouritism, we'll put the player's own faction layer first
+ if (PLAYER.team == 'RESISTANCE') {
+ window.addLayerGroup('Player Tracker Resistance', plugin.playerTracker.drawnTracesRes, true);
+ window.addLayerGroup('Player Tracker Enlightened', plugin.playerTracker.drawnTracesEnl, true);
+ } else {
+ window.addLayerGroup('Player Tracker Enlightened', plugin.playerTracker.drawnTracesEnl, true);
+ window.addLayerGroup('Player Tracker Resistance', plugin.playerTracker.drawnTracesRes, true);
+ }
map.on('layeradd',function(obj) {
- if(obj.layer === plugin.playerTracker.drawnTraces)
- {
+ if(obj.layer === plugin.playerTracker.drawnTracesEnl || obj.layer === plugin.playerTracker.drawnTracesRes) {
obj.layer.eachLayer(function(marker) {
if(marker._icon) window.setupTooltips($(marker._icon));
});
@@ -77,7 +84,8 @@ window.plugin.playerTracker.stored = {};
window.plugin.playerTracker.zoomListener = function() {
var ctrl = $('.leaflet-control-layers-selector + span:contains("Player Tracker")').parent();
if(window.map.getZoom() < window.PLAYER_TRACKER_MIN_ZOOM) {
- window.plugin.playerTracker.drawnTraces.clearLayers();
+ window.plugin.playerTracker.drawnTracesEnl.clearLayers();
+ window.plugin.playerTracker.drawnTracesRes.clearLayers();
ctrl.addClass('disabled').attr('title', 'Zoom in to show those.');
} else {
ctrl.removeClass('disabled').attr('title', '');
@@ -241,9 +249,10 @@ window.plugin.playerTracker.ago = function(time, now) {
window.plugin.playerTracker.drawData = function() {
var gllfe = plugin.playerTracker.getLatLngFromEvent;
- var layer = plugin.playerTracker.drawnTraces;
- var polyLineByAge = [[], [], [], []];
+ var polyLineByAgeEnl = [[], [], [], []];
+ var polyLineByAgeRes = [[], [], [], []];
+
var split = PLAYER_TRACKER_MAX_TIME / 4;
var now = new Date().getTime();
$.each(plugin.playerTracker.stored, function(pguid, playerData) {
@@ -259,7 +268,11 @@ window.plugin.playerTracker.drawData = function() {
var p = playerData.events[i];
var ageBucket = Math.min(parseInt((now - p.time) / split), 4-1);
var line = [gllfe(p), gllfe(playerData.events[i-1])];
- polyLineByAge[ageBucket].push(line);
+
+ if(playerData.team === 'RESISTANCE')
+ polyLineByAgeRes[ageBucket].push(line);
+ else
+ polyLineByAgeEnl[ageBucket].push(line);
}
// tooltip for marker
@@ -310,19 +323,23 @@ window.plugin.playerTracker.drawData = function() {
}
});
+ // marker opacity
+ var relOpacity = 1 - (now - last.time) / window.PLAYER_TRACKER_MAX_TIME
+ var absOpacity = window.PLAYER_TRACKER_MIN_OPACITY + (1 - window.PLAYER_TRACKER_MIN_OPACITY) * relOpacity;
+
// 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});
+ 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'); });
- m.addTo(layer);
+ m.addTo(playerData.team === 'RESISTANCE' ? plugin.playerTracker.drawnTracesRes : plugin.playerTracker.drawnTracesEnl);
plugin.playerTracker.oms.addMarker(m);
// jQueryUI doesn’t automatically notice the new markers
window.setupTooltips($(m._icon));
});
// draw the poly lines to the map
- $.each(polyLineByAge, function(i, polyLine) {
+ $.each(polyLineByAgeEnl, function(i, polyLine) {
if(polyLine.length === 0) return true;
var opts = {
@@ -333,7 +350,20 @@ window.plugin.playerTracker.drawData = function() {
dashArray: "5,8"
};
- L.multiPolyline(polyLine, opts).addTo(layer);
+ L.multiPolyline(polyLine, opts).addTo(plugin.playerTracker.drawnTracesEnl);
+ });
+ $.each(polyLineByAgeRes, function(i, polyLine) {
+ if(polyLine.length === 0) return true;
+
+ var opts = {
+ weight: 2-0.25*i,
+ color: PLAYER_TRACKER_LINE_COLOUR,
+ clickable: false,
+ opacity: 1-0.2*i,
+ dashArray: "5,8"
+ };
+
+ L.multiPolyline(polyLine, opts).addTo(plugin.playerTracker.drawnTracesRes);
});
}
@@ -343,11 +373,15 @@ window.plugin.playerTracker.handleData = function(data) {
plugin.playerTracker.discardOldData();
plugin.playerTracker.processNewData(data);
// remove old popups
- plugin.playerTracker.drawnTraces.eachLayer(function(layer) {
+ 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.drawnTraces.clearLayers();
+ plugin.playerTracker.drawnTracesEnl.clearLayers();
+ plugin.playerTracker.drawnTracesRes.clearLayers();
plugin.playerTracker.drawData();
}
diff --git a/plugins/portal-names.user.js b/plugins/portal-names.user.js
index 24ef4f57..5e902f2c 100644
--- a/plugins/portal-names.user.js
+++ b/plugins/portal-names.user.js
@@ -2,7 +2,7 @@
// @id iitc-plugin-portal-names@zaso
// @name IITC plugin: Portal Names
// @category Layer
-// @version 0.1.0.@@DATETIMEVERSION@@
+// @version 0.1.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@@ -21,7 +21,6 @@
// use own namespace for plugin
window.plugin.portalNames = function() {};
-window.plugin.portalNames.MAX_PORTALS = 250;
window.plugin.portalNames.NAME_WIDTH = 80;
window.plugin.portalNames.NAME_HEIGHT = 23;
@@ -88,38 +87,49 @@ window.plugin.portalNames.updatePortalLabels = function() {
for (var guid in window.portals) {
var p = window.portals[guid];
if (p._map) { // only consider portals added to the map
- var point = map.latLngToLayerPoint(p.getLatLng());
+ var point = map.project(p.getLatLng());
portalPoints[guid] = point;
}
}
- if (Object.keys(portalPoints).length > window.plugin.portalNames.MAX_PORTALS) {
- // too manuy VISIBLE portals to handle quickly - clear all
- window.plugin.portalNames.labelLayerGroup.clearLayers();
- window.plugin.portalNames.labelLayers = {};
- return;
- }
+ // for efficient testing of intersection, group portals into buckets based on the label size
+ var buckets = {};
+ for (var guid in portalPoints) {
+ var point = portalPoints[guid];
+ var bucketId = L.point([Math.floor(point.x/(window.plugin.portalNames.NAME_WIDTH*2)),Math.floor(point.y/window.plugin.portalNames.NAME_HEIGHT)]);
+ // the guid is added to four buckets. this way, when testing for overlap we don't need to test
+ // all 8 buckets surrounding the one around the particular portal, only the bucket it is in itself
+ var bucketIds = [bucketId, bucketId.add([1,0]), bucketId.add([0,1]), bucketId.add([1,1])];
+ for (var i in bucketIds) {
+ var b = bucketIds[i].toString();
+ if (!buckets[b]) buckets[b] = {};
+ buckets[b][guid] = true;
+ }
+ }
var coveredPortals = {};
- for (var guid in portalPoints) {
- var point = portalPoints[guid];
- // the bounds used for testing are twice as wide as the portal name marker. this is so that there's no left/right
- // overlap between two different portals text
- var largeBounds = L.bounds (
- point.subtract([window.plugin.portalNames.NAME_WIDTH,0]),
- point.add([window.plugin.portalNames.NAME_WIDTH,window.plugin.portalNames.NAME_HEIGHT])
- );
-
- for (var otherGuid in portalPoints) {
- if (guid != otherGuid) {
- var otherPoint = portalPoints[otherGuid];
-
- if (largeBounds.contains(otherPoint)) {
- // another portal is within the rectangle for this one's name - so no name for this one
- coveredPortals[guid] = true;
- break;
+ for (var bucket in buckets) {
+ var bucketGuids = buckets[bucket];
+ for (var guid in bucketGuids) {
+ var point = portalPoints[guid];
+ // the bounds used for testing are twice as wide as the portal name marker. this is so that there's no left/right
+ // overlap between two different portals text
+ var largeBounds = L.bounds (
+ point.subtract([window.plugin.portalNames.NAME_WIDTH,0]),
+ point.add([window.plugin.portalNames.NAME_WIDTH,window.plugin.portalNames.NAME_HEIGHT])
+ );
+
+ for (var otherGuid in bucketGuids) {
+ if (guid != otherGuid) {
+ var otherPoint = portalPoints[otherGuid];
+
+ if (largeBounds.contains(otherPoint)) {
+ // another portal is within the rectangle for this one's name - so no name for this one
+ coveredPortals[guid] = true;
+ break;
+ }
}
}
}
@@ -150,6 +160,7 @@ var setup = function() {
window.plugin.portalNames.labelLayerGroup = new L.LayerGroup();
window.addLayerGroup('Portal Names', window.plugin.portalNames.labelLayerGroup, true);
+ window.addHook('requestFinished', window.plugin.portalNames.updatePortalLabels);
window.addHook('mapDataRefreshEnd', window.plugin.portalNames.updatePortalLabels);
window.map.on('overlayadd overlayremove', window.plugin.portalNames.updatePortalLabels);
}
diff --git a/plugins/portals-list.user.js b/plugins/portals-list.user.js
index 089e0966..2f34d169 100644
--- a/plugins/portals-list.user.js
+++ b/plugins/portals-list.user.js
@@ -2,7 +2,7 @@
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @category Info
-// @version 0.0.16.@@DATETIMEVERSION@@
+// @version 0.0.17.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@@ -146,7 +146,7 @@ window.plugin.portalslist.getPortals = function() {
}
}else { mods[ind] = ['', '', '']; }
});
- console.log(mods);
+
var APgain= getAttackApGain(d).enemyAp;
var thisPortal = {'portal': d,
'name': name,
@@ -395,7 +395,7 @@ window.plugin.portalslist.getPortalLink = function(portal,guid) {
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
- var div = '
'+a+'
';
+ var div = '
'+a+'
';
return div;
}
@@ -416,13 +416,14 @@ var setup = function() {
$('#toolbox').append(' Portals list');
$('head').append('');
}
diff --git a/plugins/show-address.user.js b/plugins/show-address.user.js
index ee1db13d..b4765ce5 100644
--- a/plugins/show-address.user.js
+++ b/plugins/show-address.user.js
@@ -39,7 +39,7 @@ var setup = function() {
$('head').append('');
}
diff --git a/plugins/show-less-portals-zoomed-out.user.js b/plugins/show-less-portals-zoomed-out.user.js
index c61f25bd..c701f7a7 100644
--- a/plugins/show-less-portals-zoomed-out.user.js
+++ b/plugins/show-less-portals-zoomed-out.user.js
@@ -2,11 +2,11 @@
// @id iitc-plugin-show-less-portals@jonatkins
// @name IITC plugin: Show less portals when zoomed out
// @category Tweaks
-// @version 0.1.3.@@DATETIMEVERSION@@
+// @version 0.1.4.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
-// @description [@@BUILDNAME@@-@@BUILDDATE@@] Decrease the portal detail level used when zoomed out. This can speed up map loading, decrease the amount of data used, and result in faster display. Only applies when zoomed out to show no closer than L3 portals. May stop display of the smaller links/fields.
+// @description [@@BUILDNAME@@-@@BUILDDATE@@] Decrease the portal detail level used when zoomed out. This can speed up map loading, decrease the amount of data used, and solve excessive request issues. Only applies when zoomed out to show no closer than L3 portals. May stop display of the smaller links/fields.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
@@ -32,23 +32,21 @@ window.plugin.showLessPortals.setup = function() {
window.getPortalDataZoom = function() {
var mapZoom = map.getZoom();
- // this plugin only cares about close in zoom levels (zoom 13 and higher) - run the original
- // code when this isn't the case. (this way, multiple zoom-modifying plugins can exist at once - in theory)
- if (mapZoom >= 13) {
- return origGetPortalDataZoom();
+ // the latest intel site update, as of 2013-10-16, requests a silly number of map tiles at the larger zoom levels
+ // IITC matches the behaviour by default, but it makes sense to reduce the detail level sooner
+
+ // at the largest scale zooms - move back two levels
+ if (mapZoom <= 7) {
+ return Math.max(mapZoom-2,0);
}
- // make sure we're dealing with an integer here
- // (mobile: a float somehow gets through in some cases!)
- var z = parseInt(mapZoom);
+ // intermediate zoom levels - move back one
+ if (mapZoom <= 11) {
+ return Math.max(mapZoom-1,0);
+ }
- // reduce the portal zoom level by one
- z -= 1;
-
- // ensure we're not too far out
- if (z < 0) z=0;
-
- return z;
+ // otherwise revert to default behaviour
+ return origGetPortalDataZoom();
}
diff --git a/plugins/show-linked-portals.user.js b/plugins/show-linked-portals.user.js
index fe573bf4..2c82409f 100644
--- a/plugins/show-linked-portals.user.js
+++ b/plugins/show-linked-portals.user.js
@@ -130,7 +130,7 @@ var setup = function () {
'.showLinkedPortalLink2,.showLinkedPortalLink6,.showLinkedPortalLink10,.showLinkedPortalLink14 {top: 69px; }' +
'.showLinkedPortalLink3,.showLinkedPortalLink7,.showLinkedPortalLink11,.showLinkedPortalLink15 {top: 113px; }' +
'.showLinkedPortalLink4,.showLinkedPortalLink8,.showLinkedPortalLink12,.showLinkedPortalLink16 {top: 157px; }' +
- '#level{text-align:center; margin-right: 0px;}' +
+ '#level{text-align: center; margin-right: -0.5em; position: relative; right: 50%; width: 1em;}' +
'');
window.plugin.showLinkedPortal.setupCallback();
}
diff --git a/plugins/show-more-portals.user.js b/plugins/show-more-portals.user.js
index 346d690a..e119affb 100644
--- a/plugins/show-more-portals.user.js
+++ b/plugins/show-more-portals.user.js
@@ -2,11 +2,11 @@
// @id iitc-plugin-show-more-portals@jonatkins
// @name IITC plugin: Show more portals
// @category Tweaks
-// @version 0.1.3.@@DATETIMEVERSION@@
+// @version 0.1.5.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
-// @description [@@BUILDNAME@@-@@BUILDDATE@@] Boost the detail level of portals shown on the map by one zoom level when zoomed in close (L2+ portals or closer)
+// @description [@@BUILDNAME@@-@@BUILDDATE@@] Boost the detail level of portals shown so that unclaimed portals are visible when normally L1+ portals would be shown, and L2+ are visible when normally L3+ are shown
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
@@ -32,36 +32,22 @@ window.plugin.showMorePortals.setup = function() {
window.getPortalDataZoom = function() {
var mapZoom = map.getZoom();
- // this plugin only cares about close in zoom levels (zoom 13 and higher) - run the original
- // code when this isn't the case. (this way, multiple zoom-modifying plugins can exist at once - in theory)
- if (mapZoom < 13) {
- return origGetPortalDataZoom();
+ // as of 2013-10-16...
+
+ // the stock site uses the same tile size for both L1+ portals and all portals
+ // therefore, changing the L1+ zoom levels into all portals zoom level is not unfriendly to the servers
+ // (in some ways it's nicer, as IITC caches better)
+ if (mapZoom >= 15) {
+ return 17;
}
- // make sure we're dealing with an integer here
- // (mobile: a float somehow gets through in some cases!)
- var z = parseInt(mapZoom);
-
- // boost data zoom level by one
- z += 1;
-
- // not recommended on anything other than the very smallest of screens
-// // show unclaimed portals at an additional zoom level further than by default
-// if (mapZoom >= 15) z += 1;
-
-
- // limiting the mazimum zoom level for data retrieval reduces the number of requests at high zoom levels
- // (as all portal data is retrieved at z=17, why retrieve multiple z=18 tiles when fewer z=17 would do?)
- // very effective along with the new cache code
- if (z > 17) z=17;
-
- // if the data zoom is above the map zoom we can step back if the detail level is the same
- // with the new cache code this works rather well
- while (z > mapZoom && getMinPortalLevelForZoom(z) == getMinPortalLevelForZoom(z-1)) {
- z = z-1;
+ // and, the same scale for L2+ and L3+ portals. again, forcing the level down isn't unfriendly to the servers
+ // (ditto on the cacheing)
+ if (mapZoom >= 12) {
+ return 13;
}
- return z;
+ return origGetPortalDataZoom();
}
diff --git a/plugins/update-check.user.js b/plugins/update-check.user.js
new file mode 100644
index 00000000..e144332d
--- /dev/null
+++ b/plugins/update-check.user.js
@@ -0,0 +1,256 @@
+// ==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@@] 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.url = 'http://iitc.jonatkins.com/versioncheck.php?build=@@BUILDNAME@@';
+window.plugin.updateCheck.versionDataLoading = false;
+
+
+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'+match[2]+'';
+ } 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 = 'web '
+// + 'install';
+// }
+
+ if (!result.localVersion) {
+ result.html = 'version check failed';
+ } else if (!result.webVersion) {
+ result.html = 'version check failed';
+ } else if (result.upToDate) {
+ result.html = 'up to date';
+ } else if (result.outOfDate) {
+ result.html = 'out of date';
+ } else if (result.localNewer) {
+ result.html = localVerHTML+' is newer than '+webVerHTML+'(?!)';
+ } else {
+ console.warn ('Unknown case of version combinations!');
+ result.html = 'version check failed(!?)';
+ }
+
+ return result;
+}
+
+
+window.plugin.updateCheck.showReport = function(data) {
+ var result = 'WORK IN PROGRESS';
+
+ if (data.error) {
+ result += '
Error checking for updates '+data.error+'
';
+ } else {
+ if (data.name) {
+ result += '
IITC update check: '+data.name+'
';
+ }
+
+ if (data.iitc && window.script_info) {
+ var compare = window.plugin.updateCheck.compareDetails(data.iitc, window.script_info);
+ result += '
IITC Main script: '+compare.html+'
';
+
+ } else {
+ if (!data.iitc) {
+ result += '
Warning: no version information for main IITC script found in response
';
+ }
+ if (!window.script_info) {
+ result += '
Warning: your IITC script does not contain version data
';
+ }
+ }
+
+ if (data.plugins && window.bootPlugins) {
+
+ var plugins = { upToDate: [], outOfDate: [], other: [] };
+
+ if (window.bootPlugins.length == 0) {
+ result += '
No plugins installed
';
+ } else {
+ for (var i=0; iPlugins:
';
+
+ var formatRow = function(p) {
+ var status = p.status;
+ var name = p.name;
+ var statustext = p.compare && p.compare.html || '-';
+
+ return '
'+name+'
'+statustext+'
';
+ }
+
+ result += '
Out of date
';
+ for (var i in plugins.outOfDate) {
+ result += formatRow (plugins.outOfDate[i]);
+ }
+ if (plugins.outOfDate.length==0) {
+ result += '
no plugins
';
+ }
+
+ result += '
Up To Date
';
+ for (var i in plugins.upToDate) {
+ result += formatRow (plugins.upToDate[i]);
+ }
+ if (plugins.upToDate.length==0) {
+ result += '
no plugins
';
+ }
+
+ result += '
Other
';
+ for (var i in plugins.other) {
+ result += formatRow (plugins.other[i]);
+ }
+ if (plugins.other.length==0) {
+ result += '
no plugins
';
+ }
+
+ result += '
';
+ }
+
+ }
+
+ 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(' Update check');
+};
+
+var setup = window.plugin.updateCheck.setup;
+
+// PLUGIN END //////////////////////////////////////////////////////////
+
+@@PLUGINEND@@
diff --git a/plugins/zaprange.user.js b/plugins/zaprange.user.js
index 8f72383b..6057aef5 100644
--- a/plugins/zaprange.user.js
+++ b/plugins/zaprange.user.js
@@ -102,8 +102,14 @@
window.plugin.zaprange.zapLayerEnlHolderGroup.addLayer(window.plugin.zaprange.zapCircleEnlHolderGroup);
window.plugin.zaprange.zapLayerResHolderGroup.addLayer(window.plugin.zaprange.zapCircleResHolderGroup);
- window.addLayerGroup('Zaprange Enlightened', window.plugin.zaprange.zapLayerEnlHolderGroup, true);
- window.addLayerGroup('Zaprange Resistance', window.plugin.zaprange.zapLayerResHolderGroup, true);
+ // to avoid any favouritism, we'll put the player's own faction layer first
+ if (PLAYER.team == 'RESISTANCE') {
+ window.addLayerGroup('Zaprange Resistance', window.plugin.zaprange.zapLayerResHolderGroup, true);
+ window.addLayerGroup('Zaprange Enlightened', window.plugin.zaprange.zapLayerEnlHolderGroup, true);
+ } else {
+ window.addLayerGroup('Zaprange Enlightened', window.plugin.zaprange.zapLayerEnlHolderGroup, true);
+ window.addLayerGroup('Zaprange Resistance', window.plugin.zaprange.zapLayerResHolderGroup, true);
+ }
window.addHook('portalAdded', window.plugin.zaprange.portalAdded);
diff --git a/style.css b/style.css
index 377d6577..a368573e 100644
--- a/style.css
+++ b/style.css
@@ -9,7 +9,7 @@ html, body, #map {
body {
font-size: 14px;
- font-family: "roboto",arial,helvetica,sans-serif;
+ font-family: "Roboto", "Helvetica Neue", Helvetica, sans-serif;
margin: 0;
}
@@ -136,7 +136,7 @@ a:hover {
.fieldmu {
color: #FFCE00;
font-size: 13px;
- font-family: "roboto",arial,helvetica,sans-serif; /*override leaflet-container */
+ font-family: Roboto, "Helvetica Neue", Helvetica, sans-serif; /*override leaflet-container */
text-align: center;
text-shadow: 0 0 0.2em black, 0 0 0.2em black, 0 0 0.2em black;
pointer-events: none;
@@ -210,6 +210,7 @@ a:hover {
z-index: 3000;
background: rgba(8, 48, 78, 0.9);
font-size: 12.6px;
+ line-height: 15px;
color: #eee;
border: 1px solid #20A8B1;
border-bottom: 0;
@@ -255,7 +256,6 @@ em {
}
#chat td, #chatinput td {
- font-family: Verdana, sans-serif;
font-size: 12.6px;
vertical-align: top;
padding-bottom: 3px;
@@ -302,7 +302,6 @@ mark {
summary {
color: #bbb;
display: inline-block;
- font-family: Verdana,sans-serif;
height: 16px;
overflow: hidden;
padding: 0 2px;
@@ -333,7 +332,6 @@ summary {
#chatinput input {
background: transparent;
font-size: 12.6px;
- font-family: Verdana,sans-serif;
color: #EEEEEE;
width: 100%;
height: 100%;
@@ -384,6 +382,7 @@ h2 {
}
h2 #name {
+ font-weight: 300;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
@@ -472,6 +471,12 @@ input {
margin-bottom: 2px;
cursor: pointer;
}
+
+.search_not_found{
+ color:red;
+ font-style: italic;
+}
+
::-webkit-input-placeholder {
font-style: italic;
}
@@ -511,6 +516,7 @@ h3 {
background-size: contain;
cursor: help;
overflow: hidden;
+ position: relative;
}
.imgpreview img.hide {
@@ -527,6 +533,7 @@ h3 {
display: block;
margin-right: 15px;
text-align:right;
+ float: right;
}
/* portal mods */
@@ -697,7 +704,6 @@ h3 {
right: 2px;
cursor: pointer;
color: #FFCE00;
- font-family: "Arial", sans;
font-size: 16px;
}
@@ -742,7 +748,8 @@ h3 {
background-color: rgba(8, 48, 78, 0.9);
border: 1px solid #20A8B1;
color: #eee;
- font: 13px/15px Roboto, Arial, Helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 15px;
padding: 2px 4px;
}
@@ -783,6 +790,8 @@ h3 {
}
.ui-dialog-titlebar {
+ font-size: 13px;
+ line-height: 15px;
text-align: center;
padding: 4px;
background-color: rgba(8, 60, 78, 0.9);
@@ -892,7 +901,6 @@ td + td {
/* redeem results *****************************************************/
.redeem-result-table {
font-size: 14px;
- font-family: Roboto, Arial, Helvetica, sans-serif;
table-layout: fixed;
}
@@ -943,13 +951,12 @@ td + td {
color: #28f428;
}
-#portal_highlight_select{
+#portal_highlight_select {
position: absolute;
top:5px;
left:10px;
z-index: 2500;
font-size:11px;
- font-family: "roboto",arial,helvetica,sans-serif;
background-color:#0E3C46;
color:#ffce00;
@@ -970,3 +977,8 @@ td + td {
.portal_details tr.padding-top th, .portal_details tr.padding-top td {
padding-top: 0.7em;
}
+
+#play_button {
+ display: none;
+}
+
diff --git a/website/page/code/apk/ApkParser.php b/website/code/apk/ApkParser.php
similarity index 100%
rename from website/page/code/apk/ApkParser.php
rename to website/code/apk/ApkParser.php
diff --git a/website/page/code/apk/lib/ApkAndroidPlatform.php b/website/code/apk/lib/ApkAndroidPlatform.php
similarity index 100%
rename from website/page/code/apk/lib/ApkAndroidPlatform.php
rename to website/code/apk/lib/ApkAndroidPlatform.php
diff --git a/website/page/code/apk/lib/ApkArchive.php b/website/code/apk/lib/ApkArchive.php
similarity index 100%
rename from website/page/code/apk/lib/ApkArchive.php
rename to website/code/apk/lib/ApkArchive.php
diff --git a/website/page/code/apk/lib/ApkManifest.php b/website/code/apk/lib/ApkManifest.php
similarity index 100%
rename from website/page/code/apk/lib/ApkManifest.php
rename to website/code/apk/lib/ApkManifest.php
diff --git a/website/page/code/apk/lib/ApkManifestXmlElement.php b/website/code/apk/lib/ApkManifestXmlElement.php
similarity index 100%
rename from website/page/code/apk/lib/ApkManifestXmlElement.php
rename to website/code/apk/lib/ApkManifestXmlElement.php
diff --git a/website/page/code/apk/lib/ApkStream.php b/website/code/apk/lib/ApkStream.php
similarity index 100%
rename from website/page/code/apk/lib/ApkStream.php
rename to website/code/apk/lib/ApkStream.php
diff --git a/website/page/code/apk/lib/ApkXml.php b/website/code/apk/lib/ApkXml.php
similarity index 100%
rename from website/page/code/apk/lib/ApkXml.php
rename to website/code/apk/lib/ApkXml.php
diff --git a/website/page/code/apk/lib/ApkXmlParser.php b/website/code/apk/lib/ApkXmlParser.php
similarity index 100%
rename from website/page/code/apk/lib/ApkXmlParser.php
rename to website/code/apk/lib/ApkXmlParser.php
diff --git a/website/page/code/desktop-download.php b/website/code/desktop-download.php
similarity index 97%
rename from website/page/code/desktop-download.php
rename to website/code/desktop-download.php
index 7b18901d..5f1046e1 100644
--- a/website/page/code/desktop-download.php
+++ b/website/code/desktop-download.php
@@ -25,7 +25,7 @@ function loadPopularity()
{
$items = explode ( ' ', $line );
$popularity[$items[0]] = (int)$items[1];
- }
+ }
}
return $popularity;
@@ -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;
}
diff --git a/website/page/code/mobile-download.php b/website/code/mobile-download.php
similarity index 100%
rename from website/page/code/mobile-download.php
rename to website/code/mobile-download.php
diff --git a/website/page/code/url/CHANGELOG.txt b/website/code/url/CHANGELOG.txt
similarity index 100%
rename from website/page/code/url/CHANGELOG.txt
rename to website/code/url/CHANGELOG.txt
diff --git a/website/page/code/url/README.txt b/website/code/url/README.txt
similarity index 100%
rename from website/page/code/url/README.txt
rename to website/code/url/README.txt
diff --git a/website/page/code/url/url_to_absolute.php b/website/code/url/url_to_absolute.php
similarity index 100%
rename from website/page/code/url/url_to_absolute.php
rename to website/code/url/url_to_absolute.php
diff --git a/website/page/code/userscript.php b/website/code/userscript.php
similarity index 100%
rename from website/page/code/userscript.php
rename to website/code/userscript.php
diff --git a/website/page/faq.php b/website/page/faq.php
index c5d2572a..e88156ea 100644
--- a/website/page/faq.php
+++ b/website/page/faq.php
@@ -75,8 +75,6 @@ Yes it is!
Note:
-
The plugins wrapper function has to be identical to all other IITC plugins (IITCm removes it via search and replace).
- Alternatively, you can use the @@PLUGINSTART@@ / @@PLUGINEND@@ macros or remove the wrapper by hand.
The filename has to end with *.user.js.
If you don't know where to find your home directory: Enable dev-mode in the settings and follow the hint.
diff --git a/website/page/home.php b/website/page/home.php
index e8fd2093..1eda08fc 100644
--- a/website/page/home.php
+++ b/website/page/home.php
@@ -13,39 +13,37 @@ offers many more features. It is available for
Latest news
-
22nd September 2013
+
29th October 2013
-Update: IITC Mobile 0.6.5 replaces 0.6.4. This fixes a crash on entering plugin preferences on some tablets.
+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. Changes include
+
+
Fix to geodesic circle drawing. They were not correctly distorted, leading to incorrect link ranges drawn on the map.
+
Bookmarks plugin: add layer and highlighter to indicate bookmarked portals
+
Player tracker plugin: markers fade for older activity, and separate layers for each faction
+
The 'About IITC' dialog now lists which plugins are installed. This may not work correctly for 3rd party plugins at this time
+
Mobile:
+
+
Custom fullscreen preferences
+
Install to SD Card
+
Cache move to SD card option (hence the new permissions)
+
+
+
... and, as always, various bugfixes and improvements.
+
-IITC 0.14.1 and IITC Mobile 0.6.4 have been released. Changes in this version include:
-
-
Better performance when a very large number of portals are within view (country/continent level)
-
Add layer chooser options to hide resistance/enlightened portals/links/fields
-
Chat tab now remembers which was active when reloading IITC
-
Fix some shorter links not showing on the map
-
Add details of hack information (number/cooldown time, taking account of mods) and mitigation (from shields and links)
-to the portal information panel
-
Mobile
-
-
increase the size of various links on the info page to make them easier to tap
-
move the highlight selection dropdown to the native android app bar at the top
-
-
-And plugins:
-
-
Major update to bookmarks-by-zaso, including sync support
-
New features added to the resonators plugin
-
max-links plugin - start of rename to 'tidy links' - as this is a better description of what it does
-
show-linked-portals - indicate which are incoming/outgoing links in the tooltip
-
New Plugins
-
-
show-link-direction, to indicate visually which portal a link was created from
-
highlighter for portal mitigation - to show strength of defence from shields and links at a glance
-
-
-And, as always, numerous other bug fixes, tweaks and improvements.
+3RD PARTY PLUGIN AUTHORS: 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.
+
16th October 2013
+
+IITC 0.14.3 and IITC MObile 0.7.4 have just been released. This is a critical update required to work with the latest
+changes Niantic have made to the standard intel site. Additionally, the draw-tools plugin now snaps points to portals
+when creating lines/polygons/markers (was actually in 0.14.2 release), a bugfix relating to IITC not realising who
+'you' are, causing some highlighters to break, and a handful of other tweaks/bugfixes.
+
+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. Changes include
+
+
Fix to geodesic circle drawing. They were not correctly distorted, leading to incorrect link ranges drawn on the map.
+
Bookmarks plugin: add layer and highlighter to indicate bookmarked portals
+
Player tracker plugin: markers fade for older activity, and separate layers for each faction
+
The 'About IITC' dialog now lists which plugins are installed. This may not work correctly for 3rd party plugins at this time
+
Mobile:
+
+
Custom fullscreen preferences
+
Install to SD Card
+
Cache move to SD card option (hence the new permissions)
+
+
+
... and, as always, various bugfixes and improvements.
+
+
+
+3RD PARTY PLUGIN AUTHORS: 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.
+
+
+
16th October 2013
+
+IITC 0.14.3 and IITC MObile 0.7.4 have just been released. This is a critical update required to work with the latest
+changes Niantic have made to the standard intel site. Additionally, the draw-tools plugin now snaps points to portals
+when creating lines/polygons/markers (was actually in 0.14.2 release), a bugfix relating to IITC not realising who
+'you' are, causing some highlighters to break, and a handful of other tweaks/bugfixes.
+
+
+
1st October 2013
+
+IITC 0.14.2 and IITC Mobile 0.7.1 have been released. This is a critical update required to work with changes made
+to the standard intel site. Additionally, a major update to the mobile app interface has been made, and a handful
+of tweaks and bugfixes to IITC and a few plugins.
+
+
+The standard intel site now includes an 'alerts' chat tab. This will be coming to IITC in the future, but it's
+better to get this working version released without it than hold things up just for that.
+
+
22nd September 2013
Update: IITC Mobile 0.6.5 replaces 0.6.4. This fixes a crash on entering plugin preferences on some tablets.
diff --git a/website/versioncheck.php b/website/versioncheck.php
new file mode 100644
index 00000000..35e24574
--- /dev/null
+++ b/website/versioncheck.php
@@ -0,0 +1,107 @@
+ Array ( # live release
+ 'path' => 'release',
+ 'name' => 'Stable release build',
+ 'web' => 'http://iitc.jonatkins.com/?page=download',
+ ),
+ 'jonatkins-test' => Array ( # public test builds
+ 'path' => 'test',
+ 'name' => 'Test build',
+ 'web' => 'http://iitc.jonatkins.com/?page=test',
+ ),
+
+ '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',
+ ),
+
+ 'jonatkins-dev' => Array ( # personal
+ 'path' => 'dev',
+ 'name' => 'Development builds - not for public use',
+ 'web' => 'http://iitc.jonatkins.com/?page=test&build=dev',
+ ),
+
+ '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'];
+
+ // 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;
+}
+
+