diff --git a/core/code/portal_data.js b/core/code/portal_data.js index 334cb356d..f04ee24ab 100644 --- a/core/code/portal_data.js +++ b/core/code/portal_data.js @@ -1,3 +1,5 @@ +/* global L -- eslint */ + /** * @file Contain misc functions to get portal info * @module portal_data @@ -73,6 +75,50 @@ window.getPortalFieldsCount = function (guid) { return fields.length; }; +/** + * Zooms the map to a specific portal and shows its details if available. + * + * @function zoomToAndShowPortal + * @param {string} guid - The globally unique identifier of the portal. + * @param {L.LatLng|number[]} latlng - The latitude and longitude of the portal. + */ +window.zoomToAndShowPortal = function (guid, latlng) { + window.map.setView(latlng, window.DEFAULT_ZOOM); + // if the data is available, render it immediately. Otherwise defer + // until it becomes available. + if (window.portals[guid]) window.renderPortalDetails(guid); + else window.urlPortal = guid; +}; + +/** + * Selects a portal by its latitude and longitude. + * + * @function selectPortalByLatLng + * @param {number|Array|L.LatLng} lat - The latitude of the portal + * or an array or L.LatLng object containing both latitude and longitude. + * @param {number} [lng] - The longitude of the portal. + */ +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) { + window.renderPortalDetails(guid); + return; + } + } + + // not currently visible + window.urlPortalLL = [lat, lng]; + window.map.setView(window.urlPortalLL, window.DEFAULT_ZOOM); +}; + (function () { var cache = {}; var cache_level = 0; diff --git a/core/code/portal_detail_display.js b/core/code/portal_detail_display.js index e6235e528..d58662943 100644 --- a/core/code/portal_detail_display.js +++ b/core/code/portal_detail_display.js @@ -362,3 +362,62 @@ window.selectPortal = function (guid) { window.runHooks('portalSelected', { selectedPortalGuid: guid, unselectedPortalGuid: oldPortalGuid }); return update; }; + +/** + * Changes the coordinates and map scale to show the range for portal links. + * + * @function rangeLinkClick + */ +window.rangeLinkClick = function () { + if (window.portalRangeIndicator) window.map.fitBounds(window.portalRangeIndicator.getBounds()); + if (window.isSmartphone()) window.show('map'); +}; + +/** + * Creates a link to open a specific portal in Ingress Prime. + * + * @function makePrimeLink + * @param {string} guid - The globally unique identifier of the portal. + * @param {number} lat - The latitude of the portal. + * @param {number} lng - The longitude of the portal. + * @returns {string} The Ingress Prime link for the portal + */ +window.makePrimeLink = function (guid, lat, lng) { + return `https://link.ingress.com/?link=https%3A%2F%2Fintel.ingress.com%2Fportal%2F${guid}&apn=com.nianticproject.ingress&isi=576505181&ibi=com.google.ingress&ifl=https%3A%2F%2Fapps.apple.com%2Fapp%2Fingress%2Fid576505181&ofl=https%3A%2F%2Fintel.ingress.com%2Fintel%3Fpll%3D${lat}%2C${lng}`; +}; + +/** + * Generates a permalink URL based on the specified latitude and longitude and additional options. + * + * @param {L.LatLng|number[]} [latlng] - The latitude and longitude for the permalink. + * Can be omitted to create mapview-only permalink. + * @param {Object} [options] - Additional options for permalink generation. + * @param {boolean} [options.includeMapView] - Include current map view in the permalink. + * @param {boolean} [options.fullURL] - Generate a fully qualified URL (default: relative link). + * @returns {string} The generated permalink URL. + */ +window.makePermalink = function (latlng, options) { + options = options || {}; + + function round(l) { + // ensures that lat,lng are with same precision as in stock intel permalinks + return Math.floor(l * 1e6) / 1e6; + } + var args = []; + if (!latlng || options.includeMapView) { + var c = window.map.getCenter(); + args.push('ll=' + [round(c.lat), round(c.lng)].join(','), 'z=' + window.map.getZoom()); + } + if (latlng) { + if ('lat' in latlng) { + latlng = [latlng.lat, latlng.lng]; + } + args.push('pll=' + latlng.join(',')); + } + var url = ''; + if (options.fullURL) { + url += new URL(document.baseURI).origin; + } + url += '/'; + return url + '?' + args.join('&'); +}; diff --git a/core/code/portal_detail_display_tools.js b/core/code/portal_detail_display_tools.js index d02a9f190..6b5419184 100644 --- a/core/code/portal_detail_display_tools.js +++ b/core/code/portal_detail_display_tools.js @@ -311,3 +311,27 @@ window.getMitigationText = function (d, linkCount) { return ['shielding', mitigationShort, title]; }; + +/** + * Displays a dialog with links to show the specified location on various map services. + * + * @function showPortalPosLinks + * @param {number} lat - Latitude of the location. + * @param {number} lng - Longitude of the location. + * @param {string} name - Name of the location. + */ +window.showPortalPosLinks = function (lat, lng, name) { + var encoded_name = encodeURIComponent(name); + var qrcode = '
'; + var script = ""; + var gmaps = 'Google Maps'; + var bingmaps = + 'Bing Maps'; + var osm = 'OpenStreetMap'; + var latLng = '' + lat + ',' + lng + ''; + window.dialog({ + html: '
' + qrcode + script + gmaps + '; ' + bingmaps + '; ' + osm + '
' + latLng + '
', + title: name, + id: 'poslinks', + }); +}; diff --git a/core/code/utils.js b/core/code/utils.js index 059adcda8..790b6debe 100644 --- a/core/code/utils.js +++ b/core/code/utils.js @@ -224,54 +224,6 @@ const formatDistance = (distance) => { return `${IITC.utils.formatNumber(value)}${unit}`; }; -/** - * Changes the coordinates and map scale to show the range for portal links. - * - * @memberof IITC.utils - * @function rangeLinkClick - */ -const rangeLinkClick = function () { - if (window.portalRangeIndicator) window.map.fitBounds(window.portalRangeIndicator.getBounds()); - if (window.isSmartphone()) window.show('map'); -}; - -/** - * Displays a dialog with links to show the specified location on various map services. - * - * @memberof IITC.utils - * @function showPortalPosLinks - * @param {number} lat - Latitude of the location. - * @param {number} lng - Longitude of the location. - * @param {string} name - Name of the location. - */ -const showPortalPosLinks = (lat, lng, name) => { - const encodedName = encodeURIComponent(name); - - const qrcodeContainer = `
`; - const qrcodeScript = ``; - - const gmapsLink = `Google Maps`; - const bingmapsLink = `Bing Maps`; - const osmLink = `OpenStreetMap`; - - const latLngDisplay = `${lat}, ${lng}`; - - const content = ` -
- ${qrcodeContainer} - ${qrcodeScript} - ${gmapsLink}; ${bingmapsLink}; ${osmLink}
- ${latLngDisplay} -
- `; - - window.dialog({ - html: content, - title: name, - id: 'poslinks', - }); -}; - /** * Checks if the device is a touch-enabled device. * Alias for `L.Browser.touch()` @@ -296,52 +248,6 @@ const scrollBottom = (elm) => { return element.scrollHeight - element.clientHeight - element.scrollTop; }; -/** - * Zooms the map to a specific portal and shows its details if available. - * - * @memberof IITC.utils - * @function zoomToAndShowPortal - * @param {string} guid - The globally unique identifier of the portal. - * @param {L.LatLng|number[]} latlng - The latitude and longitude of the portal. - */ -const zoomToAndShowPortal = function (guid, latlng) { - window.map.setView(latlng, window.DEFAULT_ZOOM); - // if the data is available, render it immediately. Otherwise defer - // until it becomes available. - if (window.portals[guid]) window.renderPortalDetails(guid); - else window.urlPortal = guid; -}; - -/** - * Selects a portal by its latitude and longitude. - * - * @memberof IITC.utils - * @function selectPortalByLatLng - * @param {number|Array|L.LatLng} lat - The latitude of the portal - * or an array or L.LatLng object containing both latitude and longitude. - * @param {number} [lng] - The longitude of the portal. - */ -const 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) { - window.renderPortalDetails(guid); - return; - } - } - - // not currently visible - window.urlPortalLL = [lat, lng]; - window.map.setView(window.urlPortalLL, window.DEFAULT_ZOOM); -}; - /** * Escapes special characters in a string for use in JavaScript. * (for strings passed as parameters to html onclick="..." for example) @@ -532,52 +438,6 @@ const isPointInPolygon = (polygon, point) => { return !!inside; }; -/** - * Creates a link to open a specific portal in Ingress Prime. - * - * @memberof IITC.utils - * @function makePrimeLink - * @param {string} guid - The globally unique identifier of the portal. - * @param {number} lat - The latitude of the portal. - * @param {number} lng - The longitude of the portal. - * @returns {string} The Ingress Prime link for the portal - */ -const makePrimeLink = function (guid, lat, lng) { - return `https://link.ingress.com/?link=https%3A%2F%2Fintel.ingress.com%2Fportal%2F${guid}&apn=com.nianticproject.ingress&isi=576505181&ibi=com.google.ingress&ifl=https%3A%2F%2Fapps.apple.com%2Fapp%2Fingress%2Fid576505181&ofl=https%3A%2F%2Fintel.ingress.com%2Fintel%3Fpll%3D${lat}%2C${lng}`; -}; - -/** - * Generates a permalink URL based on the specified latitude and longitude and additional options. - * - * @memberof IITC.utils - * @param {L.LatLng|number[]} [latlng] - The latitude and longitude for the permalink. - * Can be omitted to create mapview-only permalink. - * @param {Object} [options={}] - Additional options for permalink generation. - * @param {boolean} [options.includeMapView=false] - Include current map view in the permalink. - * @param {boolean} [options.fullURL=false] - Generate a fully qualified URL (default: relative link). - * @returns {string} The generated permalink URL. - */ -const makePermalink = (latlng, options = {}) => { - const { includeMapView = false, fullURL = false } = options; - - // Rounds latitude/longitude to match stock intel permalinks precision - const round = (l) => Math.floor(l * 1e6) / 1e6; - - const params = []; - if (!latlng || includeMapView) { - const center = window.map.getCenter(); - params.push(`ll=${round(center.lat)},${round(center.lng)}`); - params.push(`z=${window.map.getZoom()}`); - } - if (latlng) { - const [lat, lng] = 'lat' in latlng ? [latlng.lat, latlng.lng] : latlng; - params.push(`pll=${lat},${lng}`); - } - const baseURL = fullURL ? new URL(document.baseURI).origin : ''; - - return `${baseURL}/?${params.join('&')}`; -}; - IITC.utils = { getURLParam, getCookie, @@ -590,12 +450,8 @@ IITC.utils = { unixTimeToHHmm, formatInterval, formatDistance, - rangeLinkClick, - showPortalPosLinks, isTouchDevice, scrollBottom, - zoomToAndShowPortal, - selectPortalByLatLng, escapeJavascriptString, escapeHtmlSpecialChars, prettyEnergy, @@ -606,8 +462,6 @@ IITC.utils = { clampLatLng, clampLatLngBounds, isPointInPolygon, - makePrimeLink, - makePermalink, }; // Map of legacy function names to their new names (or the same name if not renamed) @@ -623,12 +477,8 @@ const legacyFunctionMappings = { unixTimeToHHmm: 'unixTimeToHHmm', formatInterval: 'formatInterval', formatDistance: 'formatDistance', - rangeLinkClick: 'rangeLinkClick', - showPortalPosLinks: 'showPortalPosLinks', isTouchDevice: 'isTouchDevice', scrollBottom: 'scrollBottom', - zoomToAndShowPortal: 'zoomToAndShowPortal', - selectPortalByLatLng: 'selectPortalByLatLng', escapeJavascriptString: 'escapeJavascriptString', escapeHtmlSpecialChars: 'escapeHtmlSpecialChars', prettyEnergy: 'prettyEnergy', @@ -639,8 +489,6 @@ const legacyFunctionMappings = { clampLatLng: 'clampLatLng', clampLatLngBounds: 'clampLatLngBounds', pnpoly: 'isPointInPolygon', - makePrimeLink: 'makePrimeLink', - makePermalink: 'makePermalink', }; // Set up synchronization between `window` and `IITC.utils` with new names diff --git a/test/utils.spec.js b/test/utils.spec.js index 8cb9df749..93a8461d8 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -449,60 +449,3 @@ describe('IITC.utils.clamp', () => { expect(result).to.equal(-5); }); }); -describe('IITC.utils.makePermalink', () => { - beforeEach(() => { - // Mock window.map object - window.map = { - getCenter: () => ({ lat: 51.505, lng: -0.09 }), - getZoom: () => 13, - }; - - // Mock document.baseURI - Object.defineProperty(document, 'baseURI', { - value: 'https://intel.ingress.com/intel', - }); - }); - - it('should create a basic permalink with map view only', () => { - const permalink = IITC.utils.makePermalink(); - expect(permalink).to.equal('/?ll=51.505,-0.09&z=13'); - }); - - it('should create permalink with specific coordinates', () => { - const latlng = [52.52, 13.405]; - const permalink = IITC.utils.makePermalink(latlng); - expect(permalink).to.equal('/?pll=52.52,13.405'); - }); - - it('should create permalink with L.LatLng object', () => { - const latlng = { lat: 52.52, lng: 13.405 }; - const permalink = IITC.utils.makePermalink(latlng); - expect(permalink).to.equal('/?pll=52.52,13.405'); - }); - - it('should include map view when includeMapView option is true', () => { - const latlng = [52.52, 13.405]; - const permalink = IITC.utils.makePermalink(latlng, { includeMapView: true }); - expect(permalink).to.equal('/?ll=51.505,-0.09&z=13&pll=52.52,13.405'); - }); - - it('should create full URL when fullURL option is true', () => { - const latlng = [52.52, 13.405]; - const permalink = IITC.utils.makePermalink(latlng, { fullURL: true }); - expect(permalink).to.equal('https://intel.ingress.com/?pll=52.52,13.405'); - }); - - it('should handle both fullURL and includeMapView options', () => { - const latlng = [52.52, 13.405]; - const permalink = IITC.utils.makePermalink(latlng, { - fullURL: true, - includeMapView: true, - }); - expect(permalink).to.equal('https://intel.ingress.com/?ll=51.505,-0.09&z=13&pll=52.52,13.405'); - }); - - it('should handle no coordinates but includeMapView option', () => { - const permalink = IITC.utils.makePermalink(null, { includeMapView: true }); - expect(permalink).to.equal('/?ll=51.505,-0.09&z=13'); - }); -});