diff --git a/build.py b/build.py
index 42b1e4bf..8d64942b 100755
--- a/build.py
+++ b/build.py
@@ -8,7 +8,14 @@ import base64
import sys
import os
import shutil
+import json
+import shelve
+import hashlib
+try:
+ import urllib2
+except ImportError:
+ import urllib.request as urllib2
# load settings file
from buildsettings import buildSettings
@@ -66,6 +73,33 @@ def loaderRaw(var):
fn = var.group(1)
return readfile(fn)
+def loaderMD(var):
+ fn = var.group(1)
+ # use different MD.dat's for python 2 vs 3 incase user switches versions, as they are not compatible
+ db = shelve.open('build/MDv' + str(sys.version_info.major) + '.dat')
+ if 'files' in db:
+ files = db['files']
+ else:
+ files = {}
+ file = readfile(fn)
+ filemd5 = hashlib.md5(file.encode('utf8')).hexdigest()
+ # check if file has already been parsed by the github api
+ if fn in files and filemd5 in files[fn]:
+ # use the stored copy if nothing has changed to avoid hiting the api more then the 60/hour when not signed in
+ db.close()
+ return files[fn][filemd5]
+ else:
+ url = 'https://api.github.com/markdown'
+ payload = {'text': file, 'mode': 'markdown'}
+ headers = {'Content-Type': 'application/json'}
+ req = urllib2.Request(url, json.dumps(payload).encode('utf8'), headers)
+ md = urllib2.urlopen(req).read().decode('utf8').replace('\n', '').replace('\'', '\\\'')
+ files[fn] = {}
+ files[fn][filemd5] = md
+ db['files'] = files
+ db.close()
+ return md
+
def loaderImage(var):
fn = var.group(1)
return 'data:image/png;base64,{0}'.format(base64.encodestring(open(fn, 'rb').read()).decode('utf8').replace('\n', ''))
@@ -86,6 +120,7 @@ def doReplacements(script,updateUrl,downloadUrl):
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)
script = re.sub('@@INCLUDEIMAGE:([0-9a-zA-Z_./-]+)@@', loaderImage, script)
script = script.replace('@@BUILDDATE@@', buildDate)
@@ -156,6 +191,14 @@ for fn in glob.glob("plugins/*.user.js"):
metafn = fn.replace('.user.js', '.meta.js')
saveScriptAndMeta(script, os.path.join(outDir,fn), os.path.join(outDir,metafn))
+def copytree(src, dst, symlinks=False, ignore=None):
+ for item in os.listdir(src):
+ s = os.path.join(src, item)
+ d = os.path.join(dst, item)
+ if os.path.isdir(s):
+ shutil.copytree(s, d, symlinks, ignore)
+ else:
+ shutil.copy2(s, d)
# if we're building mobile too
if buildMobile:
@@ -169,7 +212,12 @@ if buildMobile:
pass
shutil.copy(os.path.join(outDir,"total-conversion-build.user.js"), "mobile/assets/iitc.js")
- # TODO? also copy plugins - once the mobile app supports plugins, that is
+ # also copy plugins
+ try:
+ os.makedirs("mobile/assets/plugins")
+ except:
+ pass
+ copytree(os.path.join(outDir,"plugins"), "mobile/assets/plugins")
# now launch 'ant' to build the mobile project
diff --git a/code/map_data.js b/code/map_data.js
index f367284b..a4998d4f 100644
--- a/code/map_data.js
+++ b/code/map_data.js
@@ -47,7 +47,7 @@ window.requestData = function() {
portalRenderLimit.init();
// finally send ajax requests
$.each(tiles, function(ind, tls) {
- data = { minLevelOfDetail: -1 };
+ data = { zoom: map.getZoom() };
data.boundsParamsList = tls;
window.requests.add(window.postAjax('getThinnedEntitiesV2', data, window.handleDataResponse, window.handleFailedRequest));
});
diff --git a/code/map_data_calc_tools.js b/code/map_data_calc_tools.js
index 2f383197..eca1b7e9 100644
--- a/code/map_data_calc_tools.js
+++ b/code/map_data_calc_tools.js
@@ -1,5 +1,4 @@
-
// MAP DATA REQUEST CALCULATORS //////////////////////////////////////
// Ingress Intel splits up requests for map data (portals, links,
// fields) into tiles. To get data for the current viewport (i.e. what
@@ -23,9 +22,9 @@ window.calculateR = function(convCenterLat) {
}
window.convertLatLngToPoint = function(latlng, magic, R) {
- var x = (magic/2 + latlng.lng * magic / 360)*R;
+ var x = (magic + latlng.lng * magic / 180)*R;
var l = Math.sin(latlng.lat * DEG2RAD);
- var y = (magic/2 + 0.5*Math.log((1+l)/(1-l)) * -(magic / (2*Math.PI)))*R;
+ var y = (magic + Math.log((1+l)/(1-l)) * -(magic / (2*Math.PI)))*R;
return {x: Math.floor(x/magic), y: Math.floor(y/magic)};
}
@@ -35,13 +34,13 @@ window.convertPointToLatLng = function(x, y, magic, R) {
// orig function put together from all over the place
// lat: (2 * Math.atan(Math.exp((((y + 1) * magic / R) - (magic/ 2)) / (-1*(magic / (2 * Math.PI))))) - Math.PI / 2) / (Math.PI / 180),
// shortened version by your favorite algebra program.
- lat: (360*Math.atan(Math.exp(Math.PI - 2*Math.PI*(y+1)/R)))/Math.PI - 90,
- lng: 360*x/R-180
+ lat: (360*Math.atan(Math.exp(Math.PI - Math.PI*(y+1)/R)))/Math.PI - 90,
+ lng: 180*x/R-180
};
e.ne = {
//lat: (2 * Math.atan(Math.exp(((y * magic / R) - (magic/ 2)) / (-1*(magic / (2 * Math.PI))))) - Math.PI / 2) / (Math.PI / 180),
- lat: (360*Math.atan(Math.exp(Math.PI - 2*Math.PI*y/R)))/Math.PI - 90,
- lng: 360*(x+1)/R-180
+ lat: (360*Math.atan(Math.exp(Math.PI - Math.PI*y/R)))/Math.PI - 90,
+ lng: 180*(x+1)/R-180
};
return e;
}
@@ -49,20 +48,7 @@ window.convertPointToLatLng = function(x, y, magic, R) {
// calculates the quad key for a given point. The point is not(!) in
// lat/lng format.
window.pointToQuadKey = function(x, y) {
- var quadkey = [];
- for(var c = window.map.getZoom(); c > 0; c--) {
- // +-------+ quadrants are probably ordered like this
- // | 0 | 1 |
- // |---|---|
- // | 2 | 3 |
- // |---|---|
- var quadrant = 0;
- var e = 1 << c - 1;
- (x & e) != 0 && quadrant++; // push right
- (y & e) != 0 && (quadrant++, quadrant++); // push down
- quadkey.push(quadrant);
- }
- return quadkey.join("");
+ return window.map.getZoom() + "_" + x + "_" + y;
}
// given quadkey and bounds, returns the format as required by the
diff --git a/code/utils_misc.js b/code/utils_misc.js
index 84562c92..4d12fcd9 100644
--- a/code/utils_misc.js
+++ b/code/utils_misc.js
@@ -1,7 +1,8 @@
// UTILS + MISC ///////////////////////////////////////////////////////
window.aboutIITC = function(){
- var v = '@@BUILDNAME@@-@@BUILDDATE@@'
+ var v = '@@BUILDNAME@@-@@BUILDDATE@@';
+ var attrib = '@@INCLUDEMD:ATTRIBUTION.md@@';
var a = ''
+ '
About IITC
'
+ ' Ingress Intel Total Conversion
'
@@ -20,8 +21,11 @@ window.aboutIITC = function(){
+ ' MapQuest OSM tiles Courtesy of MapQuest
'
+ ' '
+ '
'
- + ' Version: ' + v + '
';
- alert(a);
+ + ' Version: ' + v + '
'
+ + '
'
+ + ' ' + attrib + '
';
+ alert(a, true, function() {$('.ui-dialog').removeClass('ui-dialog-aboutIITC');});
+ $('.ui-dialog').addClass('ui-dialog-aboutIITC');
}
diff --git a/main.js b/main.js
index 42da45b7..f87807ad 100644
--- a/main.js
+++ b/main.js
@@ -1,7 +1,7 @@
// ==UserScript==
// @id ingress-intel-total-conversion@jonatkins
// @name IITC: Ingress intel map total conversion
-// @version 0.10.5.@@DATETIMEVERSION@@
+// @version 0.11.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
diff --git a/mobile/.gitignore b/mobile/.gitignore
index a56e372f..42222e62 100644
--- a/mobile/.gitignore
+++ b/mobile/.gitignore
@@ -7,3 +7,4 @@ libs/
proguard-project.txt
local.properties
assets/iitc.js
+assets/plugins/
diff --git a/mobile/AndroidManifest.xml b/mobile/AndroidManifest.xml
index d3fa4d8f..844d7462 100644
--- a/mobile/AndroidManifest.xml
+++ b/mobile/AndroidManifest.xml
@@ -1,8 +1,8 @@
+ android:versionCode="11"
+ android:versionName="0.3" >
UI
+ Plugins
+ Available plugins
Force desktop mode
Nice for tablets, looks awful on smartphones
Developer options
diff --git a/mobile/res/xml/preferences.xml b/mobile/res/xml/preferences.xml
index fd50c037..2d72b3e1 100644
--- a/mobile/res/xml/preferences.xml
+++ b/mobile/res/xml/preferences.xml
@@ -17,6 +17,10 @@
android:title="@string/pref_force_desktop"
android:summary="@string/pref_force_desktop_sum"
android:defaultValue="false" />
+
asset_list = new ArrayList();
+ ArrayList asset_values = new ArrayList();
+
+ for (int i = 0; i < asset_array.length ; i++) {
+ if (asset_array[i].endsWith("user.js")) {
+ // find user plugin name for user readable entries
+ Scanner s = null;
+ String src = "";
+ try {
+ s = new Scanner(am.open("plugins/" + asset_array[i])).useDelimiter("\\A");
+ } catch (IOException e2) {
+ // TODO Auto-generated catch block
+ e2.printStackTrace();
+ }
+ if (s != null) src = s.hasNext() ? s.next() : "";
+ 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";
+ 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];
+ }
+ asset_list.add(plugin_name);
+ // real value
+ asset_values.add(asset_array[i]);
+ }
+ }
+
+ Bundle bundle = getIntent().getExtras();
+ bundle.putStringArray("ASSETS", (String[]) asset_list.toArray(new String[0]));
+ bundle.putStringArray("ASSETS_VAL", (String[]) asset_values.toArray(new String[0]));
+ settings.setArguments(bundle);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java b/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java
index 34e3c0c0..5a68f307 100644
--- a/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java
+++ b/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java
@@ -6,6 +6,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
+import android.preference.MultiSelectListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceFragment;
@@ -21,7 +22,12 @@ public class IITC_SettingsFragment extends PreferenceFragment {
iitc_version = getArguments().getString("iitc_version");
addPreferencesFromResource(R.xml.preferences);
-
+
+ //plugins
+ MultiSelectListPreference pref_plugins = (MultiSelectListPreference) findPreference("pref_plugins");
+ pref_plugins.setEntries(getArguments().getStringArray("ASSETS"));
+ pref_plugins.setEntryValues(getArguments().getStringArray("ASSETS_VAL"));
+
// set build version
ListPreference pref_build_version = (ListPreference) findPreference("pref_build_version");
PackageManager pm = getActivity().getPackageManager();
diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java b/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java
index d92d189d..d2a62897 100644
--- a/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java
+++ b/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java
@@ -3,6 +3,7 @@ package com.cradle.iitc_mobile;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.AssetManager;
import android.net.Uri;
import android.net.http.SslError;
import android.preference.PreferenceManager;
@@ -17,6 +18,7 @@ import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Scanner;
+import java.util.Set;
public class IITC_WebViewClient extends WebViewClient {
private static final ByteArrayInputStream style = new ByteArrayInputStream(
@@ -44,7 +46,7 @@ public class IITC_WebViewClient extends WebViewClient {
String[] attributes = header.split(" +");
String iitc_version = "not found";
for (int i = 0; i < attributes.length; i++) {
- // search vor version and use the value
+ // search for version and use the value
if (attributes[i].equals("@version")) iitc_version = attributes[i+1];
}
return iitc_version;
@@ -91,6 +93,39 @@ public class IITC_WebViewClient extends WebViewClient {
handler.proceed() ;
};
+ // plugins should be loaded after the main script is injected
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+
+ // get the plugin preferences
+ SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
+ Set plugin_list = sharedPref.getStringSet("pref_plugins", null);
+
+ // iterate through all enabled plugins and load them
+ if (plugin_list != null) {
+ AssetManager am = context.getAssets();
+ String[] plugin_array = plugin_list.toArray(new String[0]);
+
+ for(int i = 0; i < plugin_list.size(); i++) {
+ if (plugin_array[i].endsWith("user.js"));
+ {
+ Log.d("iitcm", "adding plugin " + plugin_array[i]);
+ Scanner s = null;
+ String src = "";
+ try {
+ s = new Scanner(am.open("plugins/" + plugin_array[i])).useDelimiter("\\A");
+ } catch (IOException e2) {
+ // TODO Auto-generated catch block
+ e2.printStackTrace();
+ }
+ if (s != null) src = s.hasNext() ? s.next() : "";
+ view.loadUrl("javascript:" + src);
+ }
+ }
+ }
+ }
+
// Check every external resource if it’s okay to load it and maybe replace it
// with our own content. This is used to block loading Niantic resources
// which aren’t required and to inject IITC early into the site.
@@ -119,6 +154,11 @@ public class IITC_WebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("ingress.com")) {
+ // reload iitc if a poslink is clicked inside the app
+ if (url.contains("intel?ll=") || (url.contains("latE6") && url.contains("lngE6"))) {
+ Log.d("iitcm", "should be an internal clicked position link...reload script for: " + url);
+ ((IITC_Mobile) context).loadUrl(url);
+ }
return false;
} else {
Log.d("iitcm", "no ingress intel link, start external app to load url: " + url);
diff --git a/plugins/player-tracker.user.js b/plugins/player-tracker.user.js
index 864a006a..7f20df6c 100644
--- a/plugins/player-tracker.user.js
+++ b/plugins/player-tracker.user.js
@@ -266,12 +266,13 @@ window.plugin.playerTracker.drawData = function() {
if(window.plugin.guessPlayerLevels !== undefined &&
window.plugin.guessPlayerLevels.fetchLevelByPlayer !== undefined) {
var playerLevel = window.plugin.guessPlayerLevels.fetchLevelByPlayer(pguid);
- if (playerLevel === undefined) playerLevel = 1; //if player level unknown, assume level 1
if(playerLevel !== undefined) {
title += 'Level '
+ playerLevel
+ (playerLevel < (window.MAX_XM_PER_LEVEL.length - 1) ? ' (guessed)' : '')
+ '';
+ } else {
+ title += 'Level unknown'
}
}
diff --git a/style.css b/style.css
index f86398d2..ad563fe2 100644
--- a/style.css
+++ b/style.css
@@ -766,6 +766,11 @@ h3 {
text-decoration: underline;
}
+.ui-dialog-aboutIITC {
+ max-width: 600px !important;
+ width: 600px !important;
+}
+
td {
padding: 0;
vertical-align: top;