PageSourceSearch

https://smartadvisormatch.com/public/dist/168A888D89E9168D3EC03F882AE29D92.js

js smartadvisormatch.com collected 2026-10-01 12:28:49 UTC 10,702 bytes, 329 lines download raw bytes

1/**
2 * Port of SA's mobile navigation, this is scaled down as there is only one
3 * level of nesting required for the meganav.
4 */
5
6$(function()
7{
8    // Initialize the navigation menu.
9    (function initializeMenu() {
10
11        var $headerButtons = $('#header .buttons'),
12            $navCategories = $headerButtons.find('.nav-categories'),
13            $body = $(document.body),
14            isAnimating = false,
15            currentYPosition = null;
16
17        // Get all the main category links after the mobile sections have been appended.
18        var $navCategoryLinks = $navCategories.find('> ul > li.has-sub:not(.nav-more) > a:not(.js-static-link)');
19
20        // Mobile: Append mobile category titles to the DOM, using the regular link titles.
21        $navCategoryLinks.each(function() {
22            var linkText = $(this).text();
23            if (linkText)
24            {
25                $(this).parent().prepend("<h4 class=\"mobile-menu-category-title js-hidden\">" + linkText + "</h4>");
26            }
27        });
28
29        // Mobile: Navigate to a sub-category on clicking a main category link.
30        $navCategoryLinks.click(function(e) {
31
32            // Since these links can be clicked on desktop, check if on tablet size and below.
33            // NOTE: There is no screen width check in the other click event listeners, because those elements should only appear on mobile/tablet.
34            if ($(document).width() <= 1120)
35            {
36                // Do not not go to the default link URL.
37                e.preventDefault();
38
39                if (isAnimating) return;
40                isAnimating = true;
41
42                var $this = $(this);
43
44                $navCategories.removeClass('overflowed');
45                $navCategories.children('ul').toggleClass('offscreen');
46
47                $this.siblings('.nav-sub-container').addClass('mobile-category-active overflowed');
48                $this.siblings('.mobile-menu-category-title').removeClass('js-hidden');
49
50                setTimeout(function () {
51                    isAnimating = false;
52                }, 500);
53            }
54        });
55
56        // Mobile: Navigate back to main categories on clicking the top titles in the sub menus.
57        $navCategories.find('.mobile-menu-category-title').click(function() {
58            if (!isAnimating)
59            {
60                var $this = $(this);
61
62                isAnimating = true;
63
64                $navCategories.children('ul').removeClass('offscreen');
65                $navCategories.addClass('overflowed');
66
67                setTimeout (function() {
68                    $this.siblings('.nav-sub-container').removeClass('mobile-category-active');
69                    $this.addClass('js-hidden');
70                    isAnimating = false;
71                }, 500);
72            }
73        });
74
75        // Mobile: Toggle the mobile menu on clicking the hamburger button, the mobile close button, or the mobile overlay (area outside the menu).
76        $('.header-mobile-menu-button, .mobile-menu-close-button, #mobile-menu-overlay').on('click', function () {
77
78            // Don't do anything if animating.
79            if (isAnimating) return;
80
81            var menuIsActive = $headerButtons.hasClass('mobile-menu-active');
82
83            $('#mobile-menu-overlay').toggle();
84            isAnimating = true;
85
86            // If menu is open, close it.
87            if (menuIsActive)
88            {
89                $headerButtons.removeClass('mobile-menu-active');
90
91                // Let the body scroll.
92                window.requestAnimationFrame(function()
93                {
94                    // Add a 'mobile-menu-open' class to the body to make it non-scrollable.
95                    $body.removeClass('mobile-menu-open')
96                        .css({
97                            top: ''
98                        });
99
100                    window.scrollTo({
101                        top: currentYPosition,
102                        behavior: 'instant'
103                    });
104                });
105
106                setTimeout(function() {
107                    // Reset elements after the menu has finished closing.
108                    $headerButtons.removeClass('mobile-menu-visible');
109                    $navCategories.children('ul').removeClass('offscreen');
110                    $navCategories.find('.nav-sub-container').removeClass('mobile-category-active');
111                }, 500);
112            }
113            else
114            {
115                // Toggle the visibility of the mobile menu, then scroll it into view.
116                $headerButtons.addClass('mobile-menu-visible');
117                setTimeout(function() {
118                    $headerButtons.addClass('mobile-menu-active');
119                }, 10);
120
121                window.requestAnimationFrame(function()
122                {
123                    // recording the current window position
124                    currentYPosition = window.scrollY;
125                    // Add a 'mobile-menu-open' class to the body to make it non-scrollable.
126                    $body.addClass('mobile-menu-open')
127                        .css({
128                            top: currentYPosition * -1 + 'px'
129                        });
130                });
131
132                // Making the menu scrollable since this class was possibly removed.
133                $navCategories.addClass('overflowed');
134            }
135
136            setTimeout(function() {
137                isAnimating = false;
138            }, 500);
139        });
140    })();
141});
142// All tracking related functionality is contained here
143// mostly ported from SA. tweaked here and there
144var smartasset = smartasset || {};
145
146smartasset.analytics = smartasset.analytics || {};
147
148/**
149 * Initialize mixpanel link tracking
150 */
151smartasset.analytics.initializeTracking = function()
152{
153    // track the page view
154    smartasset.analytics.trackPageView(true);
155
156    // track the page view in facebook
157    smartasset.analytics.facebookTrack('ViewContent');
158};
159
160/**
161 * Track page view on MixPanel and GA
162 * @param noReferer -- boolean. Set to TRUE if you do not want to override the referer
163 */
164smartasset.analytics.trackPageView = function(noReferer)
165{
166    if ($.type(noReferer) !== "boolean")
167    {
168        noReferer = false;
169    }
170
171    if (IS_DEV)
172    {
173        console.log("Tracking page-view // noReferer: " + noReferer);
174    }
175
176    // send Google "pageview", a custom Google event
177    if (typeof ga === 'function')
178    {
179        if (!noReferer)
180        {
181            var url = prefixUrl(smartasset.page.originalUrl);
182            ga('set', 'referrer', url);
183        }
184
185        // "pageview", "page", and "title" are Google Analytics keywords
186        ga('send', 'pageview', {
187            'page': window.location.pathname,
188            'title': document.title
189        });
190
191        if (IS_DEV)
192        {
193            console.log('PageView Track: ', window.location.pathname);
194        }
195
196        // Broadcast our "Page Loaded" event to all services
197        smartasset.analytics.track('Page Loaded');
198    }
199};
200
201/**
202 * Facebook tracking
203 * @param label: custom id to send to FB for tracking
204 * @param customData: a custom object sent with specifications about the event
205 */
206
207smartasset.analytics.facebookTrack = function(label, customData)
208{
209    // First check if the facebook tracker is instantiated
210    if (typeof fbq === 'function' && $.type(label) === 'string')
211    {
212        // Set the event type
213        var eventType;
214        if (label === 'ViewContent')
215        {
216            eventType = 'track';
217        }
218        else
219        {
220            eventType = 'trackCustom';
221        }
222
223        // Check if there is custom data
224        if ($.type(customData) !== 'object')
225        {
226            customData = {};
227        }
228
229        // Include UTM Campaign params
230        var queryParams = $.queryParams();
231
232        customData.utmsource = queryParams.utm_source ? queryParams.utm_source : undefined;
233        customData.utmcampaign = queryParams.utm_campaign ? queryParams.utm_campaign : undefined;
234        customData.utmmedium = queryParams.utm_medium ? queryParams.utm_medium : undefined;
235        customData.utmcontent = queryParams.utm_content ? queryParams.utm_content : undefined;
236        customData.utmterm = queryParams.utm_term ? queryParams.utm_term : undefined;
237
238        // Track the event
239        fbq(eventType, label, customData);
240
241        if (IS_DEV) {
242            console.log('Facebook Track: ' + label, customData);
243        }
244    }
245};
246
247/**
248 * Event Tracker
249 * @param mpEvent: name of the MP event
250 * @param mpParams: additional optional items to include in the MP event
251 */
252smartasset.analytics.eventTrack = function(mpEvent, mpParams)
253{
254    if ($.type(mpEvent) === 'string')
255    {
256        // Track in Google Analytics (GA) and Mixpanel (MP)
257        if ($.type(mpParams) !== 'object')
258        {
259            mpParams = {};
260        }
261
262        smartasset.analytics.track(mpEvent, mpParams);
263    }
264};
265
266/**
267 * PLEASE READ NOTES IN THE CODE ON HOW TO USE THIS!
268 * track("eventName", { value: 4, color: "Blue"})
269 *
270 * @param {string} eventKey
271 * @param {Object=} data optional object with parameters for the event.
272 * @param {boolean} skipMixpanel if true, skips sending data to Mixpanel
273 */
274smartasset.analytics.track = function(eventKey, data, skipMixpanel)
275{
276    var skipGoogleAnalytics = false,
277        eventsToSkipInGA = ['Page Loaded'];
278
279    if (eventsToSkipInGA.indexOf(eventKey) !== -1)
280    {
281        skipGoogleAnalytics = true;
282    }
283
284    // Omit events from MP
285    if (typeof skipMixpanel !== 'boolean')
286    {
287        skipMixpanel = false;
288    }
289
290    if (IS_DEV)
291    {
292        console.log('Tracking Event: ', eventKey, data);
293    }
294
295    // instantiate a copy of the data parameter that we can mutate
296    var properties = (typeof data === 'object') ? data : {};
297
298    // avoid logging an invalid key
299    if (!eventKey || typeof eventKey !== 'string')
300    {
301        console.error('Error - key is invalid');
302        return;
303    }
304
305    properties.page = window.location.pathname;
306
307    // Raise an event within the window. This is useful for detecting
308    // events in other code.
309    // NOTE: replace "createEvent" with CustomEvent when we deprecate IE8
310    if (document.createEvent && document.dispatchEvent)
311    {
312        var evt = document.createEvent('Event');
313        evt.initEvent(eventKey, true, true);
314        document.dispatchEvent(evt);
315    }
316
317    // Send event to Mixpanel
318    if (!skipMixpanel && typeof mixpanel === "object" && typeof mixpanel.track === 'function')
319    {
320        mixpanel.track(eventKey, properties);
321    }
322
323    // Send event to Google Analytics
324    if (!skipGoogleAnalytics && typeof ga === 'function')
325    {
326        ga('send', 'event', eventKey, eventKey, properties);
327    }
328};
329

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.