PageSourceSearch

https://tripgeo.com/global.js?v=369

js tripgeo.com collected 2026-09-25 21:06:12 UTC 20,742 bytes, 719 lines download raw bytes

1var GLOBAL = {};
2GLOBAL.DotNetReference = null;
3GLOBAL.SetDotnetReference = function (pDotNetReference)
4{
5    GLOBAL.DotNetReference = pDotNetReference;
6};
7
8// https://github.com/conficient/BlazorDynamicScriptLoad
9// loadScript: returns a promise that completes when the script loads
10window.loadScript = function (scriptPath)
11{
12    // console.log("load script " + scriptPath);
13
14    // check list - if already loaded we can ignore
15    if (loaded[scriptPath])
16    {
17        // console.log(scriptPath + " already loaded");
18        // return 'empty' promise
19        return new Promise(function (resolve, reject)
20        {
21            resolve();
22        });
23    }
24
25    return new Promise(function (resolve, reject)
26    {
27        // create JS library script element
28        var script = document.createElement("script");
29        script.src = scriptPath;
30        script.type = "text/javascript";
31        // console.log(scriptPath + " created");
32
33        // flag as loading/loaded
34        loaded[scriptPath] = true;
35
36        // if the script returns okay, return resolve
37        script.onload = function ()
38        {
39            // console.log(scriptPath + " loaded ok");
40            resolve(scriptPath);
41        };
42
43        // if it fails, return reject
44        script.onerror = function ()
45        {
46            console.log(scriptPath + " load failed");
47            reject(scriptPath);
48        }
49
50        // scripts will load at end of body
51        document["body"].appendChild(script);
52    });
53}
54// store list of what scripts we've loaded
55loaded = [];
56
57// Improved mobile detection
58window.isMobileDevice = function ()
59{
60    const userAgent = navigator.userAgent || navigator.vendor || window.opera;
61    return /android/i.test(userAgent) ||
62        /iPad|iPhone|iPod/.test(userAgent) ||
63        (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
64};
65
66
67window.getVisitInfo = function ()
68{
69    const referrer = document.referrer;
70    const url = window.location.href; // Get the current page URL
71    const userAgent = navigator.userAgent;
72
73    return {
74        referrer: referrer ? (new URL(referrer)).origin : "direct", // Extract origin or "direct"
75        url: url, // Current page URL
76        agent: userAgent
77    };
78    
79};
80
81// Check page is not being loaded in iframe
82window.iframeCheck = function ()
83{
84    if (window.self !== window.top)
85    {
86        // window.location.href = "/noredirect/"; // + window.location.href;
87
88        GLOBAL.DotNetReference.invokeMethodAsync('OnRedirect');
89    }
90};
91
92window.breakOutIframe = function ()
93{
94    if (window.self !== window.top)
95    {
96        window.top.location.href = window.location.href;
97    }
98};
99
100// encryption
101function urlBase64ToUint8Array(base64String)
102{
103    const padding = '='.repeat((4 - base64String.length % 4) % 4);
104    const base64 = (base64String + padding)
105        .replace(/\-/g, '+')
106        .replace(/_/g, '/');
107
108    const rawData = atob(base64);
109    return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)));
110}
111
112function uint8ArrayToUrlBase64(uint8Array)
113{
114    const base64String = btoa(String.fromCharCode.apply(null, uint8Array));
115    return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
116}
117
118window.cryptoHelper = {
119    async encrypt(data, keyBase64, ivBase64)
120    {
121        const encoder = new TextEncoder();
122        const encodedData = encoder.encode(data);
123        const key = urlBase64ToUint8Array(keyBase64);
124        const iv = urlBase64ToUint8Array(ivBase64);
125
126        const cryptoKey = await crypto.subtle.importKey(
127            'raw',
128            key,
129            { name: 'AES-GCM', length: 256 },
130            false,
131            ['encrypt']
132        );
133
134        const encryptedData = await crypto.subtle.encrypt(
135            {
136                name: 'AES-GCM',
137                iv: iv
138            },
139            cryptoKey,
140            encodedData
141        );
142
143        return uint8ArrayToUrlBase64(new Uint8Array(encryptedData));
144    },
145
146    async decrypt(encryptedDataBase64, keyBase64, ivBase64)
147    {
148        const encryptedData = urlBase64ToUint8Array(encryptedDataBase64);
149        const key = urlBase64ToUint8Array(keyBase64);
150        const iv = urlBase64ToUint8Array(ivBase64);
151
152        const cryptoKey = await crypto.subtle.importKey(
153            'raw',
154            key,
155            { name: 'AES-GCM', length: 256 },
156            false,
157            ['decrypt']
158        );
159
160        const decryptedData = await crypto.subtle.decrypt(
161            {
162                name: 'AES-GCM',
163                iv: iv
164            },
165            cryptoKey,
166            encryptedData
167        );
168
169        const decoder = new TextDecoder();
170        return decoder.decode(decryptedData);
171    }
172};
173
174
175// file save/load
176window.saveFile = (filename, content) =>
177{
178    const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
179    const link = document.createElement("a");
180    link.href = URL.createObjectURL(blob);
181    link.download = filename;
182    link.click();
183}
184
185window.loadFile = () =>
186{
187    document.getElementById('fileInput').click();
188}
189
190function downloadICSFile(filename, content)
191{
192    console.log("downloadICSFile");
193
194    var element = document.createElement('a');
195    element.setAttribute('href', 'data:text/calendar;charset=utf-8,' + encodeURIComponent(content));
196    element.setAttribute('download', filename);
197
198    element.style.display = 'none';
199    document.body.appendChild(element);
200
201    element.click();
202
203    document.body.removeChild(element);
204}
205
206// video
207function playVideo()
208{
209    var video = document.getElementById("videoPlayer");
210    video.play();
211}
212
213
214
215document.addEventListener('DOMContentLoaded', (event) =>
216{
217    var video = document.getElementById("videoPlayer");
218
219    if (video)
220    {
221        video.onmouseover = function ()
222        {
223            video.play();
224        };
225    }
226});
227
228// iframe
229function getIframeLocalStorageValue(iframeId, key)
230{
231    var iframe = document.getElementById(iframeId);
232    if (iframe && iframe.contentWindow)
233    {
234        iframe.contentWindow.postMessage({ type: 'getLocalStorageValue', key: key }, '*');
235    }
236    else
237    {
238        console.log("iframe not found");
239    }
240}
241
242window.addEventListener('message', function (event)
243{
244    if (event.data.type === 'localStorageValue')
245    {
246        // You can handle the local storage value here, for example, pass it to Blazor
247        GLOBAL.DotNetReference.invokeMethodAsync('HandleLocalStorageValue', "test");// event.data.value);
248    }
249});
250
251window.adsenseFunctions = {
252    // Adds adsbygoogle.js to the page, once. Called from MainLayout after its first render, so the script
253    // runs against the app's real DOM. It waits a frame and then a task so the render has been painted and
254    // Blazor has finished replacing the prerendered HTML first. Any adsbygoogle.push({}) made before the
255    // library arrives (AdUnit does this as it renders) just sits in the queue and is processed on load.
256    load: function ()
257    {
258        if (window.adsenseFunctions._loading || document.getElementById('tg-adsense')) return;
259        window.adsenseFunctions._loading = true;
260
261        const add = function ()
262        {
263            const script = document.createElement('script');
264            script.id = 'tg-adsense';
265            script.async = true;
266            script.crossOrigin = 'anonymous';
267            script.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5408854154696215';
268            document.head.appendChild(script);
269        };
270        requestAnimationFrame(function () { setTimeout(add, 0); });
271    },
272
273    initializeAds: function ()
274    {
275        try
276        {
277            // console.log("initialize ads");
278            (adsbygoogle = window.adsbygoogle || []).push({});
279            // console.info("initialize ads ok");
280        }
281        catch
282        {
283            // console.log("initialize ads error");
284        }
285    },
286
287    refreshAd: function (adElementId, adClient, adSlot)
288    {
289        // console.log("refresh ad");
290
291        let adElement = document.getElementById(adElementId);
292        if (adElement)
293        {
294            // console.log("refresh ad start");
295            adElement.innerHTML = "";  // Clear the current ad content
296
297            // Re-create the AdSense ins tag
298            let ins = document.createElement('ins');
299            ins.className = "adsbygoogle";
300            ins.style.display = "block";
301            ins.style.width = "100%";
302            ins.style.height = "150px";
303            ins.dataset.adClient = adClient;
304            ins.dataset.adSlot = adSlot;
305            // ins.dataset.adFormat = "auto";
306            ins.dataset.fullWidthResponsive = "true";
307
308            adElement.appendChild(ins);
309
310            // Request a new ad
311            (adsbygoogle = window.adsbygoogle || []).push({});
312
313            // console.log("refresh ad ok");
314
315        }
316        else
317        {
318            console.log("ERROR : ad div " + adElementId + " not found");
319        }
320    }
321
322};
323
324window.saveAndRestoreScroll = {
325    scrollPosition: 0,
326
327    // Save current position
328    savePosition: function ()
329    {
330        this.scrollPosition = window.scrollY;
331    },
332
333    // Restore saved position
334    restorePosition: function ()
335    {
336        window.scrollTo(0, this.scrollPosition);
337    }
338};
339
340window.scrollInterop = {
341    enableScroll: function ()
342    {
343        document.body.style.overflow = '';
344        document.documentElement.style.overflow = '';
345    },
346    disableScroll: function ()
347    {
348        document.body.style.overflow = 'hidden';
349        document.documentElement.style.overflow = 'hidden';
350    }
351};
352
353window.loadCSS = function (href)
354{
355    return new Promise((resolve, reject) =>
356    {
357        if (!document.querySelector(`link[href="${href}"]`))
358        {
359            const link = document.createElement('link');
360            link.rel = 'stylesheet';
361            link.href = href;
362            link.onload = () => resolve();
363            link.onerror = () => reject();
364            document.head.appendChild(link);
365        } else
366        {
367            resolve(); // CSS already loaded
368        }
369    });
370};
371
372window.showtop = function ()
373{
374}
375
376// Add this to wwwroot/index.html in the <script> section or to a JS file you reference
377window.setDocumentTitle = function (title)
378{
379    document.title = title;
380};
381
382// Add this to your global.js file or create a new script file
383window.fixNavMenu = function ()
384{
385    // Fix for nav menu toggle on mobile
386    document.addEventListener('DOMContentLoaded', function ()
387    {
388        // Get the navbar toggler button
389        const navbarToggler = document.querySelector('.navbar-toggler');
390
391        // Get the collapse element
392        const navMenu = document.getElementById('navMenu');
393
394        if (navbarToggler && navMenu)
395        {
396            // Add click event listener
397            navbarToggler.addEventListener('click', function ()
398            {
399                // Toggle the 'show' class on the menu
400                navMenu.classList.toggle('show');
401            });
402
403            // Check if we're on mobile and apply appropriate initial state
404            const isMobile = window.innerWidth < 641;
405            if (!isMobile)
406            {
407                navMenu.classList.add('show');
408            }
409
410            // Handle resize events
411            window.addEventListener('resize', function ()
412            {
413                const isMobile = window.innerWidth < 641;
414                if (!isMobile)
415                {
416                    navMenu.classList.add('show');
417                } else if (!navbarToggler.getAttribute('aria-expanded') === 'true')
418                {
419                    navMenu.classList.remove('show');
420                }
421            });
422        }
423    });
424
425    // Fix CSS application issues - ensure proper styles are being applied
426    function addGlobalStyle(css)
427    {
428        var head = document.getElementsByTagName('head')[0];
429        if (!head) { return; }
430        var style = document.createElement('style');
431        style.type = 'text/css';
432        style.innerHTML = css;
433        head.appendChild(style);
434    }
435
436    // Add critical styles that might be getting overridden
437    addGlobalStyle(`
438        @media (min-width: 641px) {
439            .collapse {
440                display: block !important;
441            }
442            .navbar-toggler {
443                display: none !important;
444            }
445        }
446        
447        .nav-item a {
448            color: #d7d7d7 !important;
449        }
450        
451        .nav-item a:hover, 
452        .nav-item a.active {
453            color: white !important;
454        }
455
456        .tg-sidebar {
457            background-image: linear-gradient(180deg, rgb(32, 32, 32) 0%, #FF6700 70%) !important;
458            z-index: 1000;
459        }
460    `);
461};
462
463// Add this JavaScript function to your page or any loaded JS file
464// For example, you could add it to your _Host.cshtml or an imported script
465
466window.checkImageExists = function (url)
467{
468    return new Promise((resolve) =>
469    {
470        // Create an image cache for performance
471        if (!window._imageCache)
472        {
473            window._imageCache = {};
474        }
475
476        // Check if we've already tested this URL
477        if (window._imageCache[url] !== undefined)
478        {
479            resolve(window._imageCache[url]);
480            return;
481        }
482
483        // Create a new image to test
484        const img = new Image();
485
486        // Set a short timeout (500ms) to avoid long waits
487        const timeoutId = setTimeout(() =>
488        {
489            // Image took too long to load, assume it doesn't exist
490            window._imageCache[url] = false;
491            resolve(false);
492        }, 500);
493
494        // Image loaded successfully
495        img.onload = () =>
496        {
497            clearTimeout(timeoutId);
498            window._imageCache[url] = true;
499            resolve(true);
500        };
501
502        // Image failed to load (404, etc)
503        img.onerror = () =>
504        {
505            clearTimeout(timeoutId);
506            window._imageCache[url] = false;
507            resolve(false);
508        };
509
510        // Start loading the image
511        img.src = url;
512    });
513};
514
515
516// Add this to your global.js file
517
518// Track when a navigation link is clicked
519window.navigationHelper = {
520    // Flag to track if a navigation is in progress
521    isNavigating: false,
522
523    // Function to be called when a navigation link is clicked
524    onNavLinkClick: function ()
525    {
526        // console.log("Navigation link clicked - resetting scroll position");
527        // Set the flag
528        this.isNavigating = true;
529
530        // Immediately scroll to top
531        window.scrollTo(0, 0);
532
533        // Set a safety timeout to ensure scroll position remains at top
534        // This helps with Blazor navigation which might restore scroll position
535        setTimeout(() =>
536        {
537            window.scrollTo(0, 0);
538        }, 50);
539    },
540
541    // Function to be called after navigation/rendering is complete
542    resetScrollAfterNavigation: function ()
543    {
544        if (this.isNavigating)
545        {
546            // console.log("Resetting scroll position after navigation complete");
547            window.scrollTo(0, 0);
548
549            // Reset the flag
550            this.isNavigating = false;
551        }
552    }
553};
554
555// Sidebar is a Bootstrap offcanvas drawer at every viewport width now
556// (collapsed by default, opened via the navbar-toggler), so it should
557// auto-close on nav-link click at every width, not just mobile.
558function setupMobileMenuAutoClose()
559{
560    // Get the navbar offcanvas element
561    const navMenu = document.getElementById('navMenu');
562    if (!navMenu)
563    {
564        return;
565    }
566
567    // Get all navigation links inside the navMenu
568    const navLinks = document.querySelectorAll('#navMenu .nav-link');
569
570    // Reuse the existing Bootstrap offcanvas instance (created when the
571    // toggler first opens it) rather than creating a second one.
572    const bsOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(navMenu);
573
574    // Add click event listeners to all nav links
575    navLinks.forEach(link =>
576    {
577        link.addEventListener('click', () =>
578        {
579            // Close the menu
580            bsOffcanvas.hide();
581
582            // Call our navigation helper to reset scroll position
583            window.navigationHelper.onNavLinkClick();
584        });
585    });
586}
587
588// Also, apply this to all navigation links, not just mobile menu
589document.addEventListener('DOMContentLoaded', function ()
590{
591    // Set up mobile menu
592    setupMobileMenuAutoClose();
593
594    // Get ALL navigation links anywhere in the document
595    const allNavLinks = document.querySelectorAll('a.nav-link');
596
597    // Add scroll reset to all navigation links
598    allNavLinks.forEach(link =>
599    {
600        // Skip external links (those with target="_blank" or starting with http)
601        const href = link.getAttribute('href');
602        const isExternal = link.getAttribute('target') === '_blank' ||
603            (href && (href.startsWith('http') || href.startsWith('//')));
604
605        if (!isExternal && href && href !== '#' && !link.classList.contains('scroll-handled'))
606        {
607            link.classList.add('scroll-handled');
608            link.addEventListener('click', function ()
609            {
610                window.navigationHelper.onNavLinkClick();
611            });
612        }
613    });
614});
615
616// Also run it again when Blazor is done rendering
617window.blazorExtensions = {
618    // This function can be called from Blazor after navigation
619    setupMobileMenu: function ()
620    {
621        setupMobileMenuAutoClose();
622    }
623};
624
625window.preloadImageWithTimeout = function (url, timeoutMs)
626{
627    return new Promise((resolve) =>
628    {
629        const img = new Image();
630
631        // Set timeout to prevent waiting too long
632        const timeout = setTimeout(() =>
633        {
634            console.warn("Image load timed out:", url);
635            resolve(false);
636        }, timeoutMs || 5000);
637
638        // Clear timeout if image loads or errors
639        img.onload = function ()
640        {
641            clearTimeout(timeout);
642            resolve(true);
643        };
644
645        img.onerror = function ()
646        {
647            clearTimeout(timeout);
648            console.warn("Failed to load image:", url);
649            resolve(false);
650        };
651
652        // Start loading the image
653        img.src = url;
654    });
655};
656
657window.scrollToElement = function (elementId)
658{
659    // console.log('scrollToElement called with:', elementId);
660    const element = document.getElementById(elementId);
661    if (element)
662    {
663        // console.log('Element found, scrolling...');
664        element.scrollIntoView({ behavior: 'smooth', block: 'start' });
665        return true;
666    } else
667    {
668        console.log('Element not found:', elementId);
669        return false;
670    }
671};
672
673window.lazyScrollToElement = function (elementId, maxRetries = 20, delay = 200)
674{
675    let attempts = 0;
676
677    const tryScroll = () =>
678    {
679        attempts++;
680        // console.log(`scrollToElement attempt ${attempts}/${maxRetries} for:`, elementId);
681
682        const element = document.getElementById(elementId);
683        if (element)
684        {
685            // console.log('Element found, scrolling...');
686            element.scrollIntoView({ behavior: 'smooth', block: 'start' });
687            return true;
688        } else
689        {
690            // console.log('Element not found yet:', elementId);
691
692            if (attempts < maxRetries)
693            {
694                setTimeout(tryScroll, delay);
695            } else
696            {
697                console.log('Max retries reached, element not found:', elementId);
698            }
699            return false;
700        }
701    };
702
703    tryScroll();
704};
705
706window.tripgeoFile = {
707    download: function (fileName, contentType, content)
708    {
709        const blob = new Blob([content], { type: contentType });
710        const url = URL.createObjectURL(blob);
711        const a = document.createElement('a');
712        a.href = url;
713        a.download = fileName;
714        document.body.appendChild(a);
715        a.click();
716        document.body.removeChild(a);
717        URL.revokeObjectURL(url);
718    }
719};

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.