UNPKG

iitcp

Version:

IITC Plugin creator and developer tools

1,007 lines (854 loc) 23.3 kB
/** * @fileOverview Externs for IITC * with thanks to Filip Wieland * @see http://ingress-intel-total-conversion.readthedocs.io * @externs */ window.PLAYER = {}; /** * @const {string} */ window.PLAYER.ap; /** * @const {number} */ window.PLAYER.energy; /** * @const {number} */ window.PLAYER.level; /** * @const {string} */ window.PLAYER.min_ap_for_current_level; /** * @const {string} */ window.PLAYER.min_ap_for_next_level; /** * @const {RegExp} */ window.PLAYER.nickMatcher; /** * @const {string} */ window.PLAYER.nickname; /** * @const {string} */ window.PLAYER.team; /** * @const {number} */ window.PLAYER.verified_level; /** * @const {string} */ window.PLAYER.xm_capacity; /** * Controls how often the map should refresh, in seconds, default 30. * @const {number} */ window.REFRESH; /** * Controls the extra refresh delay per zoom level, in seconds, default 5. * @const {number} */ window.ZOOM_LEVEL_ADJ; /** * Wait this long before refreshing the view after the map has been moved, in seconds, default 2.5 * @const {number} */ window.ON_MOVE_REFRESH; /** * “limit on refresh time since previous refresh, limiting repeated move refresh rate” (?), in seconds, default 10 * @const {number} */ window.MINIMUM_OVERRIDE_REFRESH; /** * Controls how long to wait between refreshing the global score, in seconds, default 15*60 (15 mins) * @const {number} */ window.REFRESH_GAME_SCORE; /** * Controls how long, at most, can the map be inactive before refreshing, in secods, default 15*60 (15 mins) * @const {number} */ window.MAX_IDLE_TIME; /** * How much space to leave for scrollbars, in pixels, default 20. * @const {number} */ window.HIDDEN_SCROLLBAR_ASSUMED_WIDTH; /** * How wide should the sidebar be, in pixels, default 300. * @const {number} */ window.SIDEBAR_WIDTH; /** * Controls requesting chat data if chat is expanded based on the pixel distance from the line currently in view and the top of history, in pixels, default 200 * @const {number} */ window.CHAT_REQUEST_SCROLL_TOP; /** * Controls height of chat when chat is collapsed, in pixels, default 60 * @const {number} */ window.CHAT_SHRINKED; /** * Point tolerance(?) for displaying MUs, in unknown units, default 60 * @const {number} * @deprecated IITC no longer shows MU of fields due to intel changes. */ window.FIELD_MU_DISPLAY_POINT_TOLERANCE; /** * What colour should the selected portal be, string(css hex code), default ‘#f0f’ (hot pink) * @const {string} */ window.COLOR_SELECTED_PORTAL; /** * Colour hex values for teams used in portals, player names, etc. * @const {Array<string>} */ window.COLORS; /** * Colour hex values for levels, consistent with Ingress, with index 0 being white for neutral portals. * @const {Array<string>} */ window.COLORS_LVL; /** * Colour hex values for displaying mods, consistent with Ingress. Very Rare also used for AXA shields and Ultra Links. * @const {object} */ window.COLORS_MOD; /** * Colour hex values for displaying mods * @type {string} */ window.COLORS_MOD.VERY_RARE; /** * Colour hex values for displaying mods * @type {string} */ window.COLORS_MOD.RARE; /** * Colour hex values for displaying mods * @type {string} */ window.COLORS_MOD.COMMON; /** * Mod type dict for displaying mod names. * @const {object} */ window.MOD_TYPE; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.RES_SHIELD; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.MULTIHACK; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.FORCE_AMP; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.HEATSINK; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.TURRET; /** * Mod type dict for displaying mod name * @const {string} */ window.MOD_TYPE.LINK_AMPLIFIER; /** * What colour should the hacking range circle be (the small circle that appears around a selected portal, marking a ~40 metre radius), string(css colour value), default ‘orange’ * @const {string} */ window.ACCESS_INDICATOR_COLOR; /** * What colour should the linkable range circle be, string(css colour value), default ‘red’ * @const {string} */ window.RANGE_INDICATOR_COLOR; /** * “min zoom for intel map - should match that used by stock intel”, in (leaflet zoom levels?), default 3 * @const {number} */ window.MIN_ZOOM; /** * URL to blank portal image png. * @const {string} */ window.DEFAULT_PORTAL_IMG; /** * URL to call the Nominatim (geocoder?) service, string. * @const {string} */ window.NOMINATIM; /** * Resonator energy per level, 1-based array, XM * @const {Array<number>} */ window.RESO_NRG; /** * Maximum radius around a portal from which the portal is hackable, metres. * @const {number} */ window.HACK_RANGE; /** * Resonator octant cardinal directions * @const {Array<string>} */ window.OCTANTS; /** * Resonator octant arrows * @const {Array<string>} */ window.OCTANT_ARROW; /** * AP value for performing in-game action * @const {number} */ window.DESTROY_RESONATOR; /** * AP value for performing in-game action * @const {number} */ window.DESTROY_LINK; /** * AP value for performing in-game action * @const {number} */ window.DESTROY_FIELD; /** * AP value for performing in-game action * @const {number} */ window.CAPTURE_PORTAL; /** * AP value for performing in-game action * @const {number} */ window.DEPLOY_RESONATOR; /** * AP value for performing in-game action * @const {number} */ window.UPGRADE_ANOTHERS_RESONATOR; /** * AP value for performing in-game action * refers to the extra AP for deploying the last resonator on a portal. * @const {number} */ window.COMPLETION_BONUS; /** * Maximum portal level. * @const {number} */ window.MAX_PORTAL_LEVEL; /** * How many resonators of a given level can one deploy * 1-based array where the index is the resonator level. * @const {Array<number>} */ window.MAX_RESO_PER_PLAYER; /** * Faction. NONE is 0, RES is 1, ENL is 2. * @const {number} */ window.TEAM_NONE; /** * Faction. NONE is 0, RES is 1, ENL is 2. * @const {number} */ window.TEAM_RES; /** * Faction. NONE is 0, RES is 1, ENL is 2. * @const {number} */ window.TEAM_ENL; /** * Maps team to its CSS class. * ['none', 'res', 'enl'] * @const {Array<string>} */ window.TEAM_TO_CSS; /** * The Earth’s approximate radius at the equator in metres. * @const {number} */ window.EARTH_RADIUS; /** * Constant for converting degrees to radians * Math.PI / 180 * @const {number} */ window.DEG2RAD; /** * stores the id of the timeout that kicks off the next refresh (ie value returned by setTimeout()) * @type {number} */ window.refreshTimeout; /** * Portal GUID if the original URL had it. * @type {?string} */ window.urlPortal; /** * Portal lng/lat if the orignial URL had it. * @type {?string} */ window.urlPortalLL; /** * Stores the ID of the selected portal, or is null if there is none. * @type {?string} */ window.selectedPortal; /** * Reference to the linking range indicator of the selected portal. This is a Leaflet layer. * @type {?object} */ window.portalRangeIndicator; /** * Reference to the hacking range indicator of the selected portal. This is a Leaflet layer. * @type {?object} */ window.portalAccessIndicator; /** * Bool, true if the map is currently being moved. More precisely, this is true between the movestart and moveend events of the Leaflet map. * @type {boolean} */ window.mapRunsUserAction; /** * References to Leaflet objects for portals. These are indexed by the entity ID in an object * @type {object<string, object>} */ window.portals; /** * References to Leaflet objects for links. These are indexed by the entity ID in an object * @type {object<string, object>} */ window.links; /** * References to Leaflet objects for fields. These are indexed by the entity ID in an object * @type {object<string, object>} */ window.fields; /** * From when NIA provided resonator data * @type {object} * @deprecated */ window.resonators; /** * An object, where the keys are layer names and their values are bools true if the layer is enabled. Should mirror the layer selector UI. * * Note: The variable comment states that “you should use :function:`window.isLayerGroupDisplayed(name)` to check the [layer] status” * @type {object<string, boolean>} */ window.overlayStatus; /** * A noop function/namespace/”plugin framework”. * @nosideeffects */ window.plugin = function() {}; /** * A list of hooks that should be called after IITC has finished booting. Mostly used to initialise plugins. Note: These will not run if some blacklisted plugins are detected. * @type {?Array<function>} */ window.bootPlugins; /** * Object to store all open dialogs. { Element.id: Element} * @type {object} */ window.DIALOGS; /** * Count of open dialogs * @type {number} */ window.DIALOG_COUNT; /** * The HTML Element of the dialog in focus * @type {?HTMLElement} */ window.DIALOG_FOCUS; /** * * @type {?number} */ window.DIALOG_ID; /** * The time in ms it takes for the animation of minimising dialogs * @type {number} */ window.DIALOG_SLIDE_DURATION; /** * @type {boolean} */ window.IS_DEVICE_MOBILE; /** * @type {boolean} */ window.IS_DEVICE_TABLET; /** * @type {boolean} */ window.IS_VERSION_MOBILE; /** * Object storing the map info * @type {object} */ window.MAP_PARAMS; /** * Store map center lat * @type {number} */ window.MAP_PARAMS.lat; /** * Store map center lng * @type {number} */ window.MAP_PARAMS.lng; /** * Store map zoom * @type {number} */ window.MAP_PARAMS.zoom; /** * Controls what is displayed on map tiles * @type {object} */ window.TILE_PARAMS; /** * @type {Array<number>} */ window.TILE_PARAMS.ZOOM_TO_LINK_LENGTH; /** * @type {Array<number>} */ window.TILE_PARAMS.ZOOM_TO_LEVEL; /** * @type {Array<number>} */ window.TILE_PARAMS.TILES_PER_EDGE; /** * Array of names of IITC hooks * @type {Array<string>} */ window.VALID_HOOKS; /** * Calls each callback for a given hook * @param {string} event the name of the hook * @param {*} data any info to supply to each callback * @return {boolean} True if all callbacks were called without error */ window.runHooks = function(event, data) {}; /** * helper method to allow plugins to create new hooks * @param {string} event the name of the hook to create */ window.pluginCreateHook = function(event) {}; /** * Provide a callback to be called when a hook is run * @param {string} event the name of the hook * @param {funcion(?*)} callback will be called when the hook runs */ window.addHook = function(event, callback) {}; /** * Remove a function from the hook * callback must the SAME function to be unregistered. * @param {string} event the name of the hook * @param {function(?*)} callback the callback that was originaly provided */ window.removeHook = function(event, callback) {}; /** * Launches the abouth IITC Dialog * @nosideeffects */ window.aboutIITC = function() {}; /** * @type {Array<any>} */ window.activeRequests; /** * @type {number} */ window.failedRequestCount; /** * @type {number} */ window.statusTotalMapTiles; /** * @type {number} */ window.statusCachedMapTiles; /** * @type {number} */ window.statusSuccessMapTiles; /** * @type {number} */ window.statusStaleMapTiles; /** * @type {number} */ window.statusErrorMapTiles; /** * @nosideeffects */ window.requests = function() {}; /** * Returns the number of Layers in a LayerGroup * @param {*} layerGroup Leaflet layerGroup object * @returns {number} */ window.layerGroupLength = function(layerGroup) {}; /** * retrieves parameter from the URL?query=string. * @param {string} param the key you are looking for * @returns \{{{type}}\} {{description}}{{}} * @returns {string} */ window.getURLParam = function(param) {}; // read cookie by name. // http://stackoverflow.com/a/5639455/1684530 by cwolves /** * read cookie by name. * @see http://stackoverflow.com/a/5639455/1684530 * @param {string} name the cookie you want * @returns {string} */ window.readCookie = function(name) {}; /** * Add a cookie * @param {string} name name of cookie * @param {string} val value of cookie */ window.writeCookie = function(name, val) {}; /** * Expire a cookie * @param {string} name The name of the cookie to expire */ window.eraseCookie = function(name) {}; /** * certain values were stored in cookies, but we're better off using localStorage instead - make it easy to convert * @param {string} name name of cookie to convert */ window.convertCookieToLocalStorage = function(name) {}; /** * add thousand separators to given number. * U+2009 - Thin Space. Recommended for use as a thousands separator... * @see http://stackoverflow.com/a/1990590/1684530 by Doug Neiner. * @see https://en.wikipedia.org/wiki/Space_(punctuation)#Table_of_spaces * @param {(number|string)} d the number to separate * @returns {string} */ window.digits = function(d) {}; /** * The age old left pad problem * @param {number} number the number to left pad * @param {number} pad number of chars to be * @returns {string} */ window.zeroPad = function(number, pad) {}; // converts javascript timestamps to HH:mm:ss format if it was today; // /** * converts javascript timestamps to HH:mm:ss format if it was today, * otherwise it returns YYYY-MM-DD * @param {(string|number)} time unix epoch milliseconds * @param {boolean} full use tru to return both date and time * @returns {string} */ window.unixTimeToString = function(time, full) {}; // converts a javascript time to a precise date and time (optionally with millisecond precision) // formatted in ISO-style YYYY-MM-DD hh:mm:ss.mmm - but using local timezone /** * converts a javascript time to a precise date and time (optionally with millisecond precision) formatted in ISO-style YYYY-MM-DD hh:mm:ss.mmm - but using local timezone * @param {(number|string)} time unix epoch milliseconds * @param {boolean} millisecond flag to include milliseconds in return value * @returns {string} */ window.unixTimeToDateTimeString = function(time, millisecond) {}; /** * Converts Unix milliseconds to HH:mm * @param {(number|string)} time unix epoch milliseconds * @returns {string} */ window.unixTimeToHHmm = function(time) {}; /** * Converts seconds into a human readable amount of d,h,m,s * @param {number} seconds number of seconds * @param {number} maxTerms level of accuracy, d/h/m/s * @returns {string} */ window.formatInterval = function(seconds, maxTerms) {}; /** * Moves the map to show the range the portal can link to */ window.rangeLinkClick = function() {}; /** * Show portal links for sharing * @param {number} lat Latitude of portal * @param {number} lng Longitude of portal * @param {?string} name Name of portal */ window.showPortalPosLinks = function(lat, lng, name) {}; /** * @returns {boolean} true if touch screen */ window.isTouchDevice = function() {}; /** * If android, copy text * @param {string} text text to copy * @returns {boolean} true if not android copied */ window.androidCopy = function(text) {}; /** * Attempts to create a link to share for android * @returns {boolean} true if not android */ window.androidPermalink = function() {}; /** * Get Minimum portal level for current zoom * @returns {number} Min portal level */ window.getMinPortalLevel = function() {}; // 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; }; window.selectPortalByLatLng = function(lat, lng) { if (lng === undefined && lat instanceof Array) { lng = lat[1]; lat = lat[0]; } else if (lng === undefined && lat instanceof L.LatLng) { lng = lat.lng; lat = lat.lat; } for (var guid in window.portals) { var latlng = window.portals[guid].getLatLng(); if (latlng.lat == lat && latlng.lng == lng) { renderPortalDetails(guid); return; } } // not currently visible urlPortalLL = [lat, lng]; map.setView(urlPortalLL, 17); }; 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 ''; var title = detail[2] ? ' title="' + escapeHtmlSpecialChars(detail[2]) + '"' : ''; if (index % 2 === 0) return ( '<tr><td' + title + '>' + detail[1] + '</td><th' + title + '>' + detail[0] + '</th>' ); else return ( ' <th' + title + '>' + detail[0] + '</th><td' + title + '>' + detail[1] + '</td></tr>' ); }).join(''); if (t.length % 2 === 1) t + '<td></td><td></td></tr>'; 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, '<br>'); 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 = '<table>'; $.each(data, function(i, row) { table += '<tr>'; $.each(data[i], function(k, cell) { var attributes = ''; if (k === 0 && data[i].length < columnCount) { attributes = ' colspan="' + (columnCount - data[i].length + 1) + '"'; } table += '<td' + attributes + '>' + cell + '</td>'; }); table += '</tr>'; }); table += '</table>'; return table; }; // Given 3 sets of points in an array[3]{lat, lng} returns the area of the triangle window.calcTriArea = function(p) { return Math.abs( (p[0].lat * (p[1].lng - p[2].lng) + p[1].lat * (p[2].lng - p[0].lng) + p[2].lat * (p[0].lng - p[1].lng)) / 2 ); }; // Update layerGroups display status to window.overlayStatus and localStorage 'ingress.intelmap.layergroupdisplayed' window.updateDisplayedLayerGroup = function(name, display) { overlayStatus[name] = display; localStorage['ingress.intelmap.layergroupdisplayed'] = JSON.stringify( overlayStatus ); }; // Read layerGroup status from window.overlayStatus if it was added to map, // read from cookie if it has not added to map yet. // return 'defaultDisplay' if both overlayStatus and cookie didn't have the record window.isLayerGroupDisplayed = function(name, defaultDisplay) { if (typeof overlayStatus[name] !== 'undefined') return overlayStatus[name]; convertCookieToLocalStorage('ingress.intelmap.layergroupdisplayed'); var layersJSON = localStorage['ingress.intelmap.layergroupdisplayed']; if (!layersJSON) return defaultDisplay; var layers = JSON.parse(layersJSON); // keep latest overlayStatus overlayStatus = $.extend(layers, overlayStatus); if (typeof overlayStatus[name] === 'undefined') return defaultDisplay; return overlayStatus[name]; }; window.addLayerGroup = function(name, layerGroup, defaultDisplay) { if (defaultDisplay === undefined) defaultDisplay = true; if (isLayerGroupDisplayed(name, defaultDisplay)) map.addLayer(layerGroup); layerChooser.addOverlay(layerGroup, name); }; window.removeLayerGroup = function(layerGroup) { if (!layerChooser._layers[layerGroup._leaflet_id]) throw 'Layer was not found'; // removing the layer will set it's default visibility to false (store if layer gets added again) var name = layerChooser._layers[layerGroup._leaflet_id].name; var enabled = isLayerGroupDisplayed(name); map.removeLayer(layerGroup); layerChooser.removeLayer(layerGroup); updateDisplayedLayerGroup(name, enabled); }; window.clampLat = function(lat) { // the map projection used does not handle above approx +- 85 degrees north/south of the equator if (lat > 85.051128) lat = 85.051128; else if (lat < -85.051128) lat = -85.051128; return lat; }; window.clampLng = function(lng) { if (lng > 179.999999) lng = 179.999999; else if (lng < -180.0) lng = -180.0; return lng; }; window.clampLatLng = function(latlng) { return new L.LatLng(clampLat(latlng.lat), clampLng(latlng.lng)); }; window.clampLatLngBounds = function(bounds) { return new L.LatLngBounds( clampLatLng(bounds.getSouthWest()), clampLatLng(bounds.getNorthEast()) ); }; window.getGenericMarkerSvg = function(color) { var markerTemplate = '@@INCLUDESTRING:images/marker-icon.svg.template@@'; return markerTemplate.replace(/%COLOR%/g, color); }; window.getGenericMarkerIcon = function(color, className) { return L.divIcon({ iconSize: new L.Point(25, 41), iconAnchor: new L.Point(12, 41), html: getGenericMarkerSvg(color), className: className || 'leaflet-iitc-divicon-generic-marker' }); }; window.createGenericMarker = function(ll, color, options) { options = options || {}; var markerOpt = $.extend( { icon: getGenericMarkerIcon(color || '#a24ac3') }, options ); return L.marker(ll, markerOpt); }; // Fix Leaflet: handle touchcancel events in Draggable L.Draggable.prototype._onDownOrig = L.Draggable.prototype._onDown; L.Draggable.prototype._onDown = function(e) { L.Draggable.prototype._onDownOrig.apply(this, arguments); if (e.type === 'touchstart') { L.DomEvent.on(document, 'touchcancel', this._onUp, this); } };