-
Notifications
You must be signed in to change notification settings - Fork 109
Your First Plugin
IITC has a plugin API that can be used by other userscripts to register as plugins. It also imports jQuery UI to serve as a widget toolkit, however the widgets are styled to match IITC's look.
Most plugins follow this plan:
- Create a wrapper function
- Add some extra variables to make the plugin known to IITC. Create some globals if they are not set yet.
- Put actual plugin code inside the wrapper function, with a setup function inside
- Append the setup function to the
window.bootPlugins
list - Stringify the wrapper function and inject it into the page context as an IIFE
With first-party plugins, enforcement of this plan is done by using special build-time syntax (yes, IITC is using a custom build/macro system).
Here is a simple "Hello, World" plugin that illustrates how IITC plugins work:
// ==UserScript==
// @id hello-iitc
// @name IITC Plugin: Hello World
// @category Misc
// @version 0.0.1
// @namespace https://tempuri.org/iitc/hello
// @description Hello, World plugin for IITC
// @match https://intel.ingress.com/*
// @grant none
// ==/UserScript==
// Wrapper function that will be stringified and injected
// into the document. Because of this, normal closure rules
// do not apply here.
function wrapper(plugin_info) {
// Make sure that window.plugin exists. IITC defines it as a no-op function,
// and other plugins assume the same.
if(typeof window.plugin !== 'function') window.plugin = function() {};
// Name of the IITC build for first-party plugins
plugin_info.buildName = 'hello';
// Datetime-derived version of the plugin
plugin_info.dateTimeVersion = '20150829103500';
// ID/name of the plugin
plugin_info.pluginId = 'hello';
// The entry point for this plugin.
function setup() {
alert('Hello, IITC!');
}
// Add an info property for IITC's plugin system
setup.info = plugin_info;
// Make sure window.bootPlugins exists and is an array
if (!window.bootPlugins) window.bootPlugins = [];
// Add our startup hook
window.bootPlugins.push(setup);
// If IITC has already booted, immediately run the 'setup' function
if (window.iitcLoaded && typeof setup === 'function') setup();
}
// Create a script element to hold our content script
var script = document.createElement('script');
var info = {};
// GM_info is defined by the assorted monkey-themed browser extensions
// and holds information parsed from the script header.
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
};
}
// Create a text node and our IIFE inside of it
var textContent = document.createTextNode('('+ wrapper +')('+ JSON.stringify(info) +')');
// Add some content to the script element
script.appendChild(textContent);
// Finally, inject it... wherever.
(document.body || document.head || document.documentElement).appendChild(script);
You can save this code to the hello-iitc.user.js
file.
If all goes well, after you install the userscript and refresh intel, you should see the following:
Since IITC uses jQuery UI, and jQuery UI in turn patches alert()
, no browser alert is expected.
Here's how it works:
IITC plugins are themselves user scripts, which means they have to follow userscript conventions, and share some gotchas you need to keep in mind.
// ==UserScript==
// @id hello-iitc
// @name IITC Plugin: Hello World
// @category Misc
// @version 0.0.1
// @namespace https://tempuri.org/iitc/hello
// @description Hello, World plugin for IITC
// @match https://intel.ingress.com/*
// @grant none
// ==/UserScript==
All user scripts for user scripts managers (IITC Button, Tampermonkey, GreaseMonkey, etc) should have this header. This allows them to extract metadata about the script, such as which sites it should run on, and the name and description of the script to be displayed on the script list. It's important to note the @grant none
line; otherwise, Tampermonkey will complain about the script not specifying any grants. @grant
can be used to gain access to some special userscript APIs - see @grant on GreaseSpot.
This header is also parsed by the relevant platform's monkey and provided to your script as GM_info
. For more info about the metadata block in general, see Metadata Block on GreaseSpot.
function wrapper(plugin_info) { /* ... */ }
Userscripts execute in a separate context from the page - ie. the global object is not the same as window
, however both window
and document
are accessible. The wrapper function exists to contain a script that will be injected into the page. This necessarily means the function will not close over any variables defined outside of it, as it will be stringified and added to the page's DOM as an IIFE.
Also note the plugin_info
parameter - will be needed later.
if(typeof window.plugin !== 'function') window.plugin = function() {};
The run order of userscripts is not guaranteed, so our script can be loaded before IITC gets around to creating the plugin framework. Not sure why this is a no-op function though.
// Name of the IITC build for first-party plugins
plugin_info.buildName = 'hello';
// Datetime-derived version of the plugin
plugin_info.dateTimeVersion = '20150829103500';
// ID/name of the plugin
plugin_info.pluginId = 'hello';
This is mostly for first-party plugins that are built with the same tool as IITC itself, but is included here for completeness. The standard plugin header includes this warning:
//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)
Your mileage may vary.
function setup() {
alert('Hello, IITC!');
}
This will be our entry point to the plugin, and will be called by IITC when it finishes loading (or, we will call it yourself if IITC has already loaded).
setup.info = plugin_info;
IITC expects the plugin entry point to also include some extra information about the plugin itself. Here, we use the plugin_info object for this.
// Make sure window.bootPlugins exists and is an array
if (!window.bootPlugins) window.bootPlugins = [];
// Add our startup hook
window.bootPlugins.push(setup);
// If IITC has already booted, immediately run the 'setup' function
if (window.iitcLoaded && typeof setup === 'function') setup();
Again, since there are no guarantees about the order userscripts are run in, we need to make sure window.bootPlugins
exists. We then add our entry point to that array - in case IITC has not finished loading yet, it will be called after it will. If it has, we need to call the entry point itself.
Testing for whether the setup function is indeed a function will always be true so it can be omitted, but is included in the standard IITC plugin body.
Meanwhile, back in userscript land...
var info = {};
// GM_info is defined by the assorted monkey-themed browser extensions
// and holds information parsed from the script header.
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
};
}
GM_info contains information about the userscript itself parsed from the header. You can possibly just do info = GM_info
, however that will also pass in a bunch of other things to IITC.
// Create a script element to hold our content script
var script = document.createElement('script');
// Create a text node and our IIFE inside of it
var textContent = document.createTextNode('('+ wrapper +')('+ JSON.stringify(info) +')');
// Add some content to the script element
script.appendChild(textContent);
// Finally, inject it... wherever.
(document.body || document.head || document.documentElement).appendChild(script);
Finally, to inject our script into the page, we need to create a new script element, containing a text node containing our wrapper function, and append it to the body (or head, or the document itself if necessary). Note that we have to call JSON.stringify
on the info object to pass it to the wrapper function - again, this is due to the separate-context mechanic of userscripts.
For IITC users
-
Guide on how to migrate data from an legacy version of IITC Mobile
-
(click to expand )
Cache (Data caching to prevent reloading)
Controls (Map controls/widgets)
Draw (Allow drawing things onto the current map so you may plan your next move)
Highlighter (Portal highlighters)
- Hide portal ownership
- Highlight portals by level color
- Highlight inactive portals
- Highlight portal weakness
- Highlight high level portals
- Highlight portals by my level
- Highlight portals with ornaments
- Highlight portals that need recharging
- Highlight portals with ornaments
- Highlight portals that need recharging
- Highlight portals missing resonators
- Highlight portals with infrastructure problems
Info (Display additional information)
- Available AP statistics
- Portal count
- Portals list
- Player level guess
- Localized scoreboard
- Missions
- Scoring cycle / checkpoint times
- Layer count
Layer (Additional map layers)
- Find farms on map
- Portal Level Numbers
- Overlay KML / GPX / GeoJSON
- Ingress scoring regions
- Zaprange
- Player activity tracker
- Portal Names
- Keys on map
Map Tiles (Alternative map layers)
- Stamen.com map layers
- Blank map
- Gray Google map
- Bing maps
- OpenStreetMap.org map
- Gaode (高德地图) / AutoNavi map
- Kartverket.no maps (Norway)
- Yandex maps
Portal Info (Enhanced information on the selected portal)
Tweaks (Adjust IITC settings)
Misc (Unclassified plugins)
For plugin developers
For IITC developers