diff --git a/mobile/AndroidManifest.xml b/mobile/AndroidManifest.xml index 8472c725..f5a18f1b 100644 --- a/mobile/AndroidManifest.xml +++ b/mobile/AndroidManifest.xml @@ -72,6 +72,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mobile/res/values/strings.xml b/mobile/res/values/strings.xml index 68552943..38de7c91 100644 --- a/mobile/res/values/strings.xml +++ b/mobile/res/values/strings.xml @@ -86,9 +86,8 @@
IITC Mobile is able to load external plugins too!

- • create %1$s
- • move *.user.js files there
- • plugins should be listed above the official plugins]]> + Add them by clicking the (+) icon at the top right. + The plugin files have to end with \'.user.js\' and are copied to %1$s
]]>
Share portal you can:
@@ -162,6 +161,7 @@ Clear Cookies Search Debug + Add external plugins Choose account to login Login failed. Search Locations @@ -177,4 +177,9 @@ Base Layer Overlay Layers + Install external plugin? + + IITCm was requested to install the following plugin:\n\n%1$s\n\nDo you want to proceed? + + diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_FileManager.java b/mobile/src/com/cradle/iitc_mobile/IITC_FileManager.java index 6ec999eb..c66a0ccb 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_FileManager.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_FileManager.java @@ -1,7 +1,9 @@ package com.cradle.iitc_mobile; import android.app.Activity; +import android.app.AlertDialog; import android.content.ActivityNotFoundException; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; @@ -22,11 +24,14 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.net.URL; +import java.net.URLConnection; import java.net.URLEncoder; import java.util.HashMap; @@ -118,15 +123,17 @@ public class IITC_FileManager { } private final AssetManager mAssetManager; - private final IITC_Mobile mIitc; + private final Activity mActivity; private final String mIitcPath; private final SharedPreferences mPrefs; + public static final String PLUGINS_PATH = Environment.getExternalStorageDirectory().getPath() + + "/IITC_Mobile/plugins/"; - public IITC_FileManager(final IITC_Mobile iitc) { - mIitc = iitc; - mIitcPath = Environment.getExternalStorageDirectory().getPath() + "/IITC_Mobile/"; - mPrefs = PreferenceManager.getDefaultSharedPreferences(iitc); - mAssetManager = mIitc.getAssets(); + public IITC_FileManager(final Activity activity) { + mActivity = activity; + mIitcPath = Environment.getExternalStorageDirectory().getPath() + "/Activity/"; + mPrefs = PreferenceManager.getDefaultSharedPreferences(activity); + mAssetManager = mActivity.getAssets(); } private InputStream getAssetFile(final String filename) throws IOException { @@ -135,10 +142,10 @@ public class IITC_FileManager { try { return new FileInputStream(file); } catch (final FileNotFoundException e) { - mIitc.runOnUiThread(new Runnable() { + mActivity.runOnUiThread(new Runnable() { @Override public void run() { - Toast.makeText(mIitc, "File " + mIitcPath + + Toast.makeText(mActivity, "File " + mIitcPath + "dev/" + filename + " not found. " + "Disable developer mode or add iitc files to the dev folder.", Toast.LENGTH_SHORT).show(); @@ -233,6 +240,73 @@ public class IITC_FileManager { return EMPTY; } + public void installPlugin(final String uri, final boolean invalidateHeaders) { + if (uri != null) { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mActivity); + + // set title + alertDialogBuilder.setTitle(mActivity.getString(R.string.install_dialog_top)); + + // set dialog message + String text = mActivity.getString(R.string.install_dialog_msg); + text = String.format(text, uri); + alertDialogBuilder + .setMessage(text) + .setCancelable(true) + .setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + copyPlugin(uri, invalidateHeaders); + } + }) + .setNegativeButton("No", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + // create alert dialog + AlertDialog alertDialog = alertDialogBuilder.create(); + + // show it + alertDialog.show(); + } + } + + private void copyPlugin(final String uri, final boolean invalidateHeaders) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { + final URL url = new URL(uri); + final URLConnection conn = url.openConnection(); + final String fileName = uri.substring( uri.lastIndexOf('/')+1, uri.length() ); + final InputStream is = conn.getInputStream(); + // create IITCm external plugins directory if it doesn't already exist + final File pluginsDirectory = new File(PLUGINS_PATH); + pluginsDirectory.mkdirs(); + + // create in and out streams and copy plugin + File outFile = new File(pluginsDirectory + "/" + fileName); + OutputStream os = new FileOutputStream(outFile); + IITC_FileManager.copyStream(is, os, true); + } catch (IOException e) { + Log.w(e); + } + } + }); + thread.start(); + if (invalidateHeaders) { + try { + thread.join(); + ((IITC_PluginPreferenceActivity) mActivity).invalidateHeaders(); + } catch (InterruptedException e) { + Log.w(e); + } + } + } + private class FileRequest extends WebResourceResponse implements ResponseHandler, Runnable { private Intent mData; private final String mFunctionName; @@ -258,16 +332,18 @@ public class IITC_FileManager { target.addCategory(Intent.CATEGORY_OPENABLE); try { - mIitc.startActivityForResult(Intent.createChooser(target, "Choose file"), this); + final IITC_Mobile iitc = (IITC_Mobile) mActivity; + iitc.startActivityForResult(Intent.createChooser(target, "Choose file"), this); } catch (final ActivityNotFoundException e) { - Toast.makeText(mIitc, "No activity to select a file found." + + Toast.makeText(mActivity, "No activity to select a file found." + "Please install a file browser of your choice!", Toast.LENGTH_LONG).show(); } } @Override public void onActivityResult(final int resultCode, final Intent data) { - mIitc.deleteResponseHandler(this); // to enable garbage collection + final IITC_Mobile iitc = (IITC_Mobile) mActivity; + iitc.deleteResponseHandler(this); // to enable garbage collection mResultCode = resultCode; mData = data; diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java index 8c619247..2cea8b6a 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java @@ -228,6 +228,13 @@ public class IITC_Mobile extends Activity .show(); } } + + if (uri.getPath().endsWith(".user.js")) { + final Intent prefIntent = new Intent(this, IITC_PluginPreferenceActivity.class); + prefIntent.putExtra("url", uri.toString()); + startActivity(prefIntent); + // TODO receive intent, start dialog if user want to install $plugin, reload IITC + } } if (Intent.ACTION_SEARCH.equals(action)) { diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_PluginPreferenceActivity.java b/mobile/src/com/cradle/iitc_mobile/IITC_PluginPreferenceActivity.java index 8c63b348..f588c272 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_PluginPreferenceActivity.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_PluginPreferenceActivity.java @@ -1,18 +1,21 @@ package com.cradle.iitc_mobile; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.Intent; import android.content.res.AssetManager; import android.os.Bundle; -import android.os.Environment; import android.preference.PreferenceActivity; import android.text.TextUtils; import android.view.LayoutInflater; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.TextView; +import android.widget.Toast; import com.cradle.iitc_mobile.fragments.PluginsFragment; @@ -29,6 +32,8 @@ import java.util.TreeMap; public class IITC_PluginPreferenceActivity extends PreferenceActivity { + private final static int COPY_PLUGIN_REQUEST = 1; + private List
mHeaders; // we use a tree map to have a map with alphabetical order // don't initialize the asset plugin map, because it tells us if the settings are started the first time @@ -39,6 +44,8 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity { new TreeMap>(); private static int mDeletedPlugins = 0; + private IITC_FileManager mFileManager; + @Override public void setListAdapter(final ListAdapter adapter) { if (adapter == null) { @@ -78,6 +85,13 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity { getIntent() .putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, PluginsFragment.class.getName()); } + + mFileManager = new IITC_FileManager(this); + + final String uri = getIntent().getStringExtra("url"); + if (uri != null) { + mFileManager.installPlugin(uri, true); + } super.onCreate(savedInstanceState); } @@ -103,17 +117,53 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity { } } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.plugins, menu); + return super.onCreateOptionsMenu(menu); + } + @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // exit settings when home button (iitc icon) is pressed onBackPressed(); return true; + case R.id.menu_plugins_add: + // create the chooser Intent + final Intent target = new Intent(Intent.ACTION_GET_CONTENT); + // iitcm only parses *.user.js scripts + target.setType("file/*"); + target.addCategory(Intent.CATEGORY_OPENABLE); + + try { + startActivityForResult(Intent.createChooser(target, "Choose file"), COPY_PLUGIN_REQUEST); + } catch (final ActivityNotFoundException e) { + Toast.makeText(this, "No activity to select a file found." + + "Please install a file browser of your choice!", Toast.LENGTH_LONG).show(); + } default: return super.onOptionsItemSelected(item); } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch(requestCode) { + case COPY_PLUGIN_REQUEST: + if (data != null && data.getData() != null) { + String filePath = data.getData().getPath(); + mFileManager.installPlugin("file://" + filePath, true); + return; + } + break; + default: + super.onActivityResult(requestCode, resultCode, data); + break; + + } + } + @Override protected boolean isValidFragment(final String s) { return true; @@ -141,9 +191,7 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity { } private File[] getUserPlugins() { - final String iitc_path = Environment.getExternalStorageDirectory().getPath() - + "/IITC_Mobile/"; - final File directory = new File(iitc_path + "plugins/"); + final File directory = new File(IITC_FileManager.PLUGINS_PATH); File[] files = directory.listFiles(); if (files == null) { files = new File[0]; @@ -164,6 +212,8 @@ public class IITC_PluginPreferenceActivity extends PreferenceActivity { if ((userPlugins.length + officialPlugins.length) != (numPlugins + mDeletedPlugins)) { Log.d("new or less plugins found since last start, rebuild preferences"); sAssetPlugins.clear(); + sUserPlugins.clear(); + mDeletedPlugins = 0; setUpPluginPreferenceScreen(); } } diff --git a/plugins/bookmarks-by-zaso.user.js b/plugins/bookmarks-by-zaso.user.js index e15075f9..f880efba 100644 --- a/plugins/bookmarks-by-zaso.user.js +++ b/plugins/bookmarks-by-zaso.user.js @@ -2,7 +2,7 @@ // @id iitc-plugin-bookmarks@ZasoGD // @name IITC plugin: Bookmarks for maps and portals // @category Controls -// @version 0.2.7.@@DATETIMEVERSION@@ +// @version 0.2.8.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ @@ -151,18 +151,11 @@ } if(newStatus === 1) { - $('#bookmarksBox').show(); - $('#bkmrksTrigger').hide(); + $('#bookmarksBox').css('height', 'auto'); + $('#bkmrksTrigger').css('height', '0'); } else { - $('#bookmarksBox').hide(); - $('#bkmrksTrigger').show(); - } - - if(window.plugin.bookmarks.isSmart) { - var button = $('#bkmrksTrigger'); - button.toggleClass('open'); - if(button.hasClass('open')) { button.text('[-] Bookmarks'); } - else{ button.text('[+] Bookmarks'); } + $('#bkmrksTrigger').css('height', '64px'); + $('#bookmarksBox').css('height', '0'); } window.plugin.bookmarks.statusBox['show'] = newStatus; @@ -433,6 +426,11 @@ } } + window.plugin.bookmarks.deleteMode = function() { + $('#bookmarksBox').toggleClass('deleteMode'); + } + + /***************************************************************************************************************************************************************/ // Saved the new sort of the folders (in the localStorage) @@ -489,6 +487,7 @@ items:"li.bookmarkFolder:not(.othersBookmarks)", handle:".bookmarksAnchor", placeholder:"sortable-placeholder", + helper:'clone', // fix accidental click in firefox forcePlaceholderSize:true, update:function(event, ui) { var typeList = $('#'+ui.item.context.id).parent().parent('.bookmarkList').attr('id'); @@ -501,6 +500,7 @@ connectWith:".bookmarkList ul ul", handle:".bookmarksLink", placeholder:"sortable-placeholder", + helper:'clone', // fix accidental click in firefox forcePlaceholderSize:true, update:function(event, ui) { var typeList = $('#'+ui.item.context.id).parent().parent().parent().parent('.bookmarkList').attr('id'); @@ -548,17 +548,22 @@ window.plugin.bookmarks.optPaste = function() { var promptAction = prompt('Press CTRL+V to paste it.', ''); if(promptAction !== null && promptAction !== '') { - localStorage[window.plugin.bookmarks.KEY_STORAGE] = promptAction; - window.plugin.bookmarks.refreshBkmrks(); - window.runHooks('pluginBkmrksEdit', {"target": "all", "action": "import"}); - console.log('BOOKMARKS: reset and imported bookmarks'); - window.plugin.bookmarks.optAlert('Successful. '); + try { + localStorage[window.plugin.bookmarks.KEY_STORAGE] = promptAction; + window.plugin.bookmarks.refreshBkmrks(); + window.runHooks('pluginBkmrksEdit', {"target": "all", "action": "import"}); + console.log('BOOKMARKS: reset and imported bookmarks'); + window.plugin.bookmarks.optAlert('Successful. '); + } catch(e) { + console.warn('BOOKMARKS: failed to import data: '+e); + window.plugin.bookmarks.optAlert('Import failed '); + } } } window.plugin.bookmarks.optReset = function() { - var promptAction = prompt('All bookmarks will be deleted. Are you sure? [Y/N]', ''); - if(promptAction !== null && (promptAction === 'Y' || promptAction === 'y')) { + var promptAction = confirm('All bookmarks will be deleted. Are you sure?', ''); + if(promptAction) { delete localStorage[window.plugin.bookmarks.KEY_STORAGE]; window.plugin.bookmarks.createStorage(); window.plugin.bookmarks.loadStorage(); @@ -618,6 +623,8 @@ if(latlngs.length >= 2 && latlngs.length <= 3) { // TODO: add an API to draw-tools rather than assuming things about it's internals var newItem; + window.plugin.drawTools.setOptions(); + if(latlngs.length == 2) { newItem = L.geodesicPolyline(latlngs, window.plugin.drawTools.lineOptions); } else { @@ -885,6 +892,7 @@ +'
' +'-' +'
...
' + +'Show/Hide "X" button' +'
' +'
' +'
Maps
' @@ -904,6 +912,7 @@ +'+ Folder' +'
' +'' + +'
' +''; plugin.bookmarks.htmlDisabledMessage = '
Plugin Bookmarks disabled*.
'; diff --git a/plugins/bookmarks-css.css b/plugins/bookmarks-css.css index 9c160667..a8630974 100644 --- a/plugins/bookmarks-css.css +++ b/plugins/bookmarks-css.css @@ -9,13 +9,20 @@ line-height:22px; text-indent:0; text-decoration:none; + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; } + #bookmarksBox{ display:block; position:absolute !important; z-index:4001; top:100px; left:100px; + width:231px; + height:auto; + overflow:hidden; } #bookmarksBox .addForm, #bookmarksBox #bookmarksTypeBar, @@ -25,33 +32,40 @@ color:#fff; font-size:14px; } -#bookmarksBox #topBar, -#bookmarksBox #topBar *{ +#bookmarksBox #topBar{ height:15px !important; } +#bookmarksBox #topBar *{ + height: 14px !important; +} #bookmarksBox #topBar *{ float:left !important; } #bookmarksBox .handle{ - text-indent:-20px; - width:209px; + width:80%; text-align:center; color:#fff; - line-height:8px; + line-height:6px; cursor:move; } #bookmarksBox #topBar .btn{ display:block; - width:19px; + width:10%; cursor:pointer; color:#20a8b1; -} -#bookmarksBox #topBar #bookmarksMin{ + font-weight:bold; text-align:center; - line-height:14px; + line-height:13px; font-size:18px; } + +#bookmarksBox #topBar #bookmarksDel{ + overflow:hidden; + text-indent:-999px; + background:#B42E2E; +} + #bookmarksBox #topBar #bookmarksMin:hover{ color:#ffce00; } @@ -59,8 +73,9 @@ clear:both; } #bookmarksBox h5{ - padding:4px 0; - width:114px; + padding:4px 0 23px; + width:50%; + height:93px !important; text-align:center; color:#788; } @@ -73,9 +88,8 @@ color:#ffce00; background:rgba(0,0,0,0); } -#bookmarksBox #topBar .btn, +#bookmarksBox #topBar, #bookmarksBox .addForm, -#bookmarksBox .handle, #bookmarksBox #bookmarksTypeBar, #bookmarksBox .bookmarkList li.bookmarksEmpty, #bookmarksBox .bookmarkList li.bkmrk a, @@ -90,16 +104,16 @@ #bookmarksBox .addForm *{ display:block; float:left; - padding:4px 8px 3px; + height:28px !important; } #bookmarksBox .addForm a{ cursor:pointer; color:#20a8b1; font-size:12px; - width:65px; + width:35%; text-align:center; line-height:20px; - padding:4px 0 3px; + padding:4px 0 23px; } #bookmarksBox .addForm a:hover{ background:#ffce00; @@ -109,15 +123,19 @@ #bookmarksBox .addForm input{ font-size:11px !important; color:#ffce00; - width:81px; - line-height:11px; + height:28px; + padding:4px 8px 1px; + line-height:12px; font-size:12px; - -webkit-box-sizing:content-box; - -moz-box-sizing:content-box; - box-sizing:content-box; } #bookmarksBox #bkmrk_portals .addForm input{ - width:147px; + width:65%; +} +#bookmarksBox #bkmrk_maps .addForm input{ + width:42%; +} +#bookmarksBox #bkmrk_maps .addForm a{ + width:29%; } #bookmarksBox .addForm input:hover, #bookmarksBox .addForm input:focus{ @@ -125,11 +143,12 @@ background:rgba(0,0,0,.6); } #bookmarksBox .bookmarkList > ul{ - width:231px; clear:both; list-style-type:none; color:#fff; overflow:hidden; + overflow-y:auto; + max-height:580px; } #bookmarksBox .sortable-placeholder{ background:rgba(8,48,78,.55); @@ -161,12 +180,12 @@ color:#eee; } #bookmarksBox ul .bookmarksRemoveFrom{ - width:19px; + width:10%; text-align:center; color:#fff; } #bookmarksBox ul .bookmarksLink{ - width:171px; + width:90%; padding:0 10px 0 8px; color:#ffce00; } @@ -174,7 +193,7 @@ color:#03fe03; } #bookmarksBox ul .othersBookmarks .bookmarksLink{ - width:190px; + width:90%; } #bookmarksBox ul .bookmarksLink:hover{ color:#03fe03; @@ -183,6 +202,8 @@ color:#fff; background:#e22 !important; } + +/*---- UI border -----*/ #bookmarksBox, #bookmarksBox *{ border-color:#20a8b1; @@ -193,40 +214,44 @@ #bookmarksBox ul .bookmarkFolder{ border-top-width:1px; } + #bookmarksBox #topBar, #bookmarksBox #bookmarksTypeBar, #bookmarksBox .addForm, #bookmarksBox ul .bookmarkFolder .folderLabel, -#bookmarksBox ul li.bkmrk{ +#bookmarksBox ul li.bkmrk a { border-bottom-width:1px; } -#bookmarksBox ul .bookmarkFolder, -#bookmarksBox ul .bookmarksRemoveFrom{ +#bookmarksBox ul .bookmarkFolder{ border-right-width:1px; border-left-width:1px; } #bookmarksBox #topBar *, #bookmarksBox #bookmarksTypeBar *, -#bookmarksBox .addForm *{ +#bookmarksBox .addForm *, +#bookmarksBox ul li.bkmrk{ border-left-width:1px; } #bookmarksBox #topBar, #bookmarksBox #bookmarksTypeBar, -#bookmarksBox .addForm{ +#bookmarksBox .addForm, +#bookmarksBox ul .bookmarksRemoveFrom{ border-right-width:1px; } -#bookmarksBox ul .othersBookmarks .bookmarksRemoveFrom, +#bookmarksBox ul .bookmarkFolder.othersBookmarks li.bkmrk, #bookmarksBox ul .bookmarkFolder .folderLabel .bookmarksRemoveFrom{ border-left-width:0; } #bkmrksTrigger{ - display:none; + display:block !important; position:absolute; + overflow:hidden; top:0; left:277px; width:47px; margin-top:-36px; height:64px; + height:0; cursor:pointer; z-index:2999; background-position:center bottom; @@ -272,17 +297,25 @@ } #bookmarksBox .bookmarkList .bkmrk.ui-sortable-helper{ border-right-width:1px; - border-left-width:1px; + border-left-width:1px !important; } #bookmarksBox .bookmarkList ul li ul li.sortable-placeholder{ height:23px; box-shadow:inset 0 -1px 0 #20a8b1,inset 1px 0 0 #20a8b1; } + #bookmarksBox .bookmarkList ul li.bookmarkFolder.ui-sortable-helper, -#bookmarksBox .bookmarkList ul li.othersBookmarks ul, #bookmarksBox .bookmarkList ul li.othersBookmarks ul li.sortable-placeholder{ box-shadow:inset 0 -1px 0 #20a8b1; } + +#bookmarksBox #topBar #bookmarksDel, +#bookmarksBox .bookmarkList .bookmarkFolder .folderLabel:hover .bookmarksRemoveFrom, +#bookmarksBox .bookmarkList .bookmarkFolder .folderLabel:hover .bookmarksAnchor{ + border-bottom-width:1px; +} + +/*---------*/ #bookmarksBox .bookmarkList .bookmarkFolder .folderLabel .bookmarksAnchor span, #bookmarksBox .bookmarkList .bookmarkFolder .folderLabel > span, #bookmarksBox .bookmarkList .bookmarkFolder .folderLabel > span > span, @@ -304,7 +337,7 @@ #bookmarksBox .bookmarkList .bookmarkFolder .folderLabel .bookmarksAnchor{ line-height:25px; color:#fff; - width:209px; + width:90%; } #bookmarksBox .bookmarkList .bookmarkFolder .folderLabel .bookmarksAnchor span{ float:left; @@ -336,6 +369,7 @@ #bookmarksBox .bookmarkList .bookmarkFolder.open .folderLabel > span, #bookmarksBox .bookmarkList .bookmarkFolder.open .folderLabel > span > span{ display:block; + display:none; } #bookmarksBox .bookmarkList .bookmarkFolder.open .folderLabel:hover > span > span{ border-color:transparent #036 transparent transparent; @@ -345,7 +379,7 @@ } #bookmarksBox .bookmarkList .bookmarkFolder ul{ display:none; - margin-left:19px; + margin-left:10%; } #bookmarksBox .bookmarkList .bookmarkFolder.open ul{ display:block; @@ -355,6 +389,26 @@ margin-left:0; } +/*---- Width for deleteMode -----*/ +#bookmarksBox .bookmarksRemoveFrom{ + display:none !important; +} +#bookmarksBox.deleteMode .bookmarksRemoveFrom{ + display:block !important; +} + +#bookmarksBox .bookmarkList .bookmarkFolder .folderLabel .bookmarksAnchor, +#bookmarksBox ul .bookmarksLink, +#bookmarksBox ul .othersBookmarks .bookmarksLink{ + width:100% !important; +} + +#bookmarksBox.deleteMode .bookmarkList .bookmarkFolder .folderLabel .bookmarksAnchor, +#bookmarksBox.deleteMode ul .bookmarksLink, +#bookmarksBox.deleteMode ul .othersBookmarks .bookmarksLink{ + width:90% !important; +} + /********************************************** MOBILE **********************************************/ @@ -367,7 +421,8 @@ margin: 0 !important; padding: 0 !important; border: 0 !important; - background: transparent !important;; + background: transparent !important; + overflow:auto !important; } #bookmarksBox.mobile .bookmarkList ul, #bookmarksBox.mobile .bookmarkList ul li, @@ -380,14 +435,27 @@ box-shadow:none !important; border-width:0 !important; } -#bookmarksBox.mobile #topBar{ +#bookmarksBox.mobile #topBar #bookmarksMin, +#bookmarksBox.mobile #topBar .handle{ display:none !important; } + +#bookmarksBox.mobile #topBar #bookmarksDel{ + width:100%; + height:34px !important; + font-size:13px; + color:#fff; + font-weight:normal; + padding-top:11px; + text-indent:0; +} + #bookmarksBox.mobile #bookmarksTypeBar h5{ cursor:pointer; text-align:center; float:left; width:50%; + height:auto !important; padding:7px 0; } #bookmarksBox.mobile #bookmarksTypeBar h5.current{ @@ -413,14 +481,14 @@ #bookmarksBox.mobile .bookmarkList li.bookmarkFolder a.bookmarksRemoveFrom, #bookmarksBox.mobile .bookmarkList li.bkmrk a.bookmarksRemoveFrom{ box-shadow:inset 0 1px 0 #20a8b1,inset -1px 0 0 #20a8b1 !important; - width:15%; + width:10%; background:none !important; } #bookmarksBox.mobile .bookmarkList li.bookmarkFolder a.bookmarksAnchor, #bookmarksBox.mobile .bookmarkList li.bkmrk a.bookmarksLink{ text-indent:10px; - width:85%; - height:21px; + height:36px; + line-height:24px; overflow:hidden; } #bookmarksBox.mobile .bookmarkList ul li.bookmarkFolder ul{ @@ -428,7 +496,6 @@ } #bookmarksBox.mobile .bookmarkList > ul{ border-bottom:1px solid #20a8b1 !important; - border-right:1px solid #20a8b1 !important; } #bookmarksBox.mobile .bookmarkList .bookmarkFolder.othersBookmarks ul{ @@ -440,14 +507,14 @@ } #bookmarksBox.mobile .bookmarkList > ul{ max-height:none; - width:85% !important; +/* width:85% !important;*/ } #bookmarksBox.mobile .bookmarkList li.bookmarkFolder .folderLabel{ box-shadow:0 1px 0 #20a8b1 !important; } #bookmarksBox.mobile .bookmarkList ul li.bookmarkFolder ul{ - width:85% !important; - margin-left:15% !important; + width:90% !important; + margin-left:10% !important; } #bookmarksBox.mobile .bookmarkList ul li.bookmarkFolder.othersBookmarks ul{ width:100% !important; @@ -461,7 +528,7 @@ } #bookmarksBox.mobile .addForm, #bookmarksBox.mobile .addForm *{ - height:35px; + height:35px !important; padding:0; } #bookmarksBox.mobile .addForm a{ @@ -469,14 +536,14 @@ } #bookmarksBox.mobile .addForm a{ - width:25% !important; +/* width:25% !important;*/ } #bookmarksBox.mobile .addForm input{ - width:50% !important; +/* width:50% !important;*/ text-indent:10px; } #bookmarksBox.mobile #bkmrk_portals .addForm input{ - width:75% !important; +/* width:75% !important;*/ } #bookmarksBox.mobile #bookmarksTypeBar h5, #bookmarksBox.mobile .bookmarkList .addForm a{ @@ -530,10 +597,10 @@ #bookmarksBox.mobile .bookmarkList .bookmarkFolder.open .folderLabel > span > span{ display:block !important; } + /********************************************** DIALOG BOX **********************************************/ - /*---- Auto Drawer -----*/ #bkmrksAutoDrawer, #bkmrksAutoDrawer p, @@ -597,4 +664,4 @@ width:96%; height:120px; resize:vertical; -} +} \ No newline at end of file diff --git a/plugins/fix-googlemap-china-offset.user.js b/plugins/fix-googlemap-china-offset.user.js new file mode 100644 index 00000000..a25b271a --- /dev/null +++ b/plugins/fix-googlemap-china-offset.user.js @@ -0,0 +1,198 @@ +// ==UserScript== +// @id iitc-plugin-fix-googlemap-china-offset@breezewish +// @name IITC plugin: Fix Google Map offsets in China +// @category Tweaks +// @version 0.0.1.@@DATETIMEVERSION@@ +// @namespace https://github.com/jonatkins/ingress-intel-total-conversion +// @updateURL @@UPDATEURL@@ +// @downloadURL @@DOWNLOADURL@@ +// @description [@@BUILDNAME@@-@@BUILDDATE@@] Show correct Google Map for China user by applying offset tweaks. +// @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.fixChinaOffset = {}; + +// Before understanding how this plugin works, you should know 3 points: +// +// Point1. +// The coordinate system of Ingress is WGS-84. +// However, the tiles of Google maps (except satellite map) in China have +// offsets (base on GCJ-02 coordinate system) by China policy. +// That means, if you request map tiles by giving GCJ-02 position, you +// will get the correct map. +// +// Point2. +// Currently there are no easy algorithm to transform from GCJ-02 to WGS-84, +// but we can easily transform data from WGS-84 to GCJ-02. +// +// Point3. +// When using Google maps in IITC, the layer structure looks like this: +// ---------------------- +// | Other Leaflet layers | (Including portals, links, fields, and so on) +// ---------------------- +// | L.Google | (Only for controling) +// ---------------------- +// | Google Map layer | (Generated by Google Map APIs, for rendering maps) +// ---------------------- +// +// When users are interacting with L.Google (for example, dragging, zooming), +// L.Google will perform the same action on the Google Map layer using Google +// Map APIs. +// +// So, here is the internal of the plugin: +// +// The plugin overwrites behaviours of L.Google. When users are dragging the map, +// L.Google will pass offseted positions to Google Map APIs (WGS-84 to GCJ-02). +// So Google Map APIs will render a correct map. +// +// The offset between Google maps and Ingress objects can also be fixed by applying +// WGS-84 to GCJ-02 transformation on Ingress objects. However we cannot simply know +// the requesting bounds of Ingress objects because we cannot transform GCJ-02 to +// WGS-84. As a result, the Ingress objects on maps would be incomplete. +// +// The algorithm of transforming WGS-84 to GCJ-02 comes from: +// https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936 +// There is no official algorithm because it is classified information. + +/////////// begin WGS84 to GCJ-02 transformer ///////// +var WGS84transformer = window.plugin.fixChinaOffset.WGS84transformer = function() {}; +// Krasovsky 1940 +// +// a = 6378245.0, 1/f = 298.3 +// b = a * (1 - f) +// ee = (a^2 - b^2) / a^2; +WGS84transformer.prototype.a = 6378245.0; +WGS84transformer.prototype.ee = 0.00669342162296594323; + +WGS84transformer.prototype.transform = function(wgLat, wgLng) { + + if(this.isOutOfChina(wgLat, wgLng)) + return {lat: wgLat, lng: wgLng}; + + dLat = this.transformLat(wgLng - 105.0, wgLat - 35.0); + dLng = this.transformLng(wgLng - 105.0, wgLat - 35.0); + radLat = wgLat / 180.0 * Math.PI; + magic = Math.sin(radLat); + magic = 1 - this.ee * magic * magic; + sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * Math.PI); + dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * Math.PI); + mgLat = wgLat + dLat; + mgLng = wgLng + dLng; + + return {lat: mgLat, lng: mgLng}; + +}; + +WGS84transformer.prototype.isOutOfChina = function(lat, lng) { + + if(lng < 72.004 || lng > 137.8347) return true; + if(lat < 0.8293 || lat > 55.8271) return true; + + return false; + +}; + +WGS84transformer.prototype.transformLat = function(x, y) { + + var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0; + + return ret; + +}; + +WGS84transformer.prototype.transformLng = function(x, y) { + + var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0; + + return ret; + +}; +/////////// end WGS84 to GCJ-02 transformer ///////// + +var WGS84toGCJ02 = new WGS84transformer(); + +/////////// begin overwrited L.Google ///////// +window.plugin.fixChinaOffset.L = {}; +window.plugin.fixChinaOffset.L.Google = { + + _update: function(e) { + + if(!this._google) return; + this._resize(); + + var center = e && e.latlng ? e.latlng : this._map.getCenter(); + + ///// modified here /// + var _center = window.plugin.fixChinaOffset.getLatLng(center, this._type); + /////////////////////// + + this._google.setCenter(_center); + this._google.setZoom(this._map.getZoom()); + + this._checkZoomLevels(); + + }, + + _handleZoomAnim: function (e) { + + var center = e.center; + + ///// modified here /// + var _center = window.plugin.fixChinaOffset.getLatLng(center, this._type); + /////////////////////// + + this._google.setCenter(_center); + this._google.setZoom(e.zoom); + + } + +} +/////////// end overwrited L.Google ///////// + +window.plugin.fixChinaOffset.getLatLng = function(pos, type) { + + // No offsets in satellite and hybrid maps + if(type !== 'SATELLITE' && type !== 'HYBRID') { + var newPos = WGS84toGCJ02.transform(pos.lat, pos.lng); + return new google.maps.LatLng(newPos.lat, newPos.lng); + } else { + return new google.maps.LatLng(pos.lat, pos.lng); + } + +}; + +window.plugin.fixChinaOffset.overwrite = function(dest, src) { + + for(var key in src) { + if(src.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + +} + +var setup = function() { + + window.plugin.fixChinaOffset.overwrite(L.Google.prototype, window.plugin.fixChinaOffset.L.Google); + +} + +// PLUGIN END ////////////////////////////////////////////////////////// + +@@PLUGINEND@@ diff --git a/website/page/faq.php b/website/page/faq.php index cf706b6b..3c4f1e93 100644 --- a/website/page/faq.php +++ b/website/page/faq.php @@ -158,19 +158,17 @@ From here you can remove/disable individual plugins or IITC itself. END ), -'mobile-plugins' => Array ( "IITC Mobile: Is it possible to add other plugins to IITC Mobile?", +'mobile-plugins' => Array ( "IITC Mobile: Is it possible to add external plugins to IITC Mobile?", <<<'END' Yes it is!
    -
  • Create a folder named "IITC_Mobile" in your home directory.
  • -
  • Inside this folder, create a new folder named "plugins".
  • -
  • Copy all your additional plugins to this folder.
  • -
  • You should see your plugins listed above the official plugins.
  • +
  • Navigate to the IITC Plugins preference screen and click the (+) icon at the top right. You can select the script using a file explorer of your choice.
  • +
  • IITCm creates a new folder in your home directory, named "IITC_Mobile". Inside this folder you'll find a "plugins" folder where all external plugins are copied to.
Note:
  • 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.
  • +
  • You need a file explorer app installed to add external plugins
END ),