1(function (root, factory) { 2 const api = factory(root); 3 if (typeof module === 'object' && module.exports) module.exports = api; 4 root.WSGTaskBuilderLauncher = api; 5}(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 6 'use strict'; 7 8 const MAX_MERCATOR_LATITUDE = 85.05112878; 9 const MAX_SAFE_TASK_NUMBER = Number.MAX_SAFE_INTEGER; 10 11 function normalizeLongitude(value) { 12 const number = Number(value); 13 if (!Number.isFinite(number)) return null; 14 const wrapped = ((number + 180) % 360 + 360) % 360 - 180; 15 return Object.is(wrapped, -0) ? 0 : wrapped; 16 } 17 18 function canonicalNumber(value, decimals, minimum, maximum) { 19 const number = Number(value); 20 if (!Number.isFinite(number)) return null; 21 const bounded = Math.min(maximum, Math.max(minimum, number)); 22 const text = bounded.toFixed(decimals).replace(/(?:\.0+|(?:(\.[0-9]*[1-9]))0+)$/, '$1'); 23 return text === '-0' ? '0' : text; 24 } 25 26 function canonicalTaskNumber(value) { 27 const number = Number(value); 28 return Number.isSafeInteger(number) && number > 0 && number <= MAX_SAFE_TASK_NUMBER ? String(number) : null; 29 } 30 31 function readLaunchState(taskBrowser) { 32 const map = taskBrowser?.tbm?.map || taskBrowser?.map; 33 const center = map && typeof map.getCenter === 'function' ? map.getCenter() : null; 34 const lat = canonicalNumber(center?.lat, 6, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE); 35 const lngValue = normalizeLongitude(center?.lng); 36 const lng = lngValue === null ? null : canonicalNumber(lngValue, 6, -180, 180); 37 const zoom = canonicalNumber(map && typeof map.getZoom === 'function' ? map.getZoom() : null, 2, 1, 18); 38 const activeTask = taskBrowser?.hasCurrentTaskDetails?.() === true 39 ? taskBrowser.currentTask 40 : null; 41 return { 42 lat, 43 lng, 44 zoom, 45 entrySeqID: canonicalTaskNumber(activeTask?.EntrySeqID) 46 }; 47 } 48 49 function buildLaunchUrl(state, baseUrl = '/taskbuilder/') { 50 const url = new URL(baseUrl, root.location?.origin || 'https://wesimglide.org'); 51 const completeView = state?.lat !== null && state?.lng !== null && state?.zoom !== null 52 && state?.lat !== undefined && state?.lng !== undefined && state?.zoom !== undefined; 53 if (completeView) { 54 url.searchParams.set('lat', String(state.lat)); 55 url.searchParams.set('lng', String(state.lng)); 56 url.searchParams.set('zoom', String(state.zoom)); 57 } 58 const taskNumber = canonicalTaskNumber(state?.entrySeqID); 59 if (taskNumber !== null) url.searchParams.set('entrySeqID', taskNumber); 60 return `${url.pathname}${url.search}`; 61 } 62 63 function prepareLink(link, taskBrowser) { 64 if (!link) return '/taskbuilder/'; 65 const href = buildLaunchUrl(readLaunchState(taskBrowser)); 66 link.setAttribute('href', href); 67 return href; 68 } 69 70 function install(documentLike = root.document) { 71 const link = documentLike?.getElementById?.('taskBuilderLauncher'); 72 if (!link) return null; 73 const prepare = () => prepareLink(link, root.TB); 74 ['pointerdown', 'focus', 'mouseenter', 'contextmenu'].forEach(type => link.addEventListener(type, prepare)); 75 link.addEventListener('click', prepare); 76 prepare(); 77 return link; 78 } 79 80 if (root.document) { 81 if (root.document.readyState === 'loading') root.document.addEventListener('DOMContentLoaded', () => install(), {once: true}); 82 else install(); 83 } 84
85 return Object.freeze({canonicalNumber, canonicalTaskNumber, normalizeLongitude, readLaunchState, buildLaunchUrl, prepareLink, install}); 86}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.