You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Maybe adding some around the null checks to let adopters know configuration may be missing, and info at some key points?
Also if this is an area we expect adopters to review more, we could also beef up the JSDocs a bit to give more context.
/* * Licensed to Apereo under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Apereo licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at the following location: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */varuportal=uportal||{};(function($){/** * Finds the appropriate property configuration for the current institution. * @returns {Object|null} The property configuration object or null if not found. */varfindPropertyConfig=function(){if(up.analytics.model==null){console.error("[Analytics] No analytics model found.");returnnull;}if(Array.isArray(up.analytics.model.hosts)){varhosts=up.analytics.model.hosts;varpropertyConfig=null;for(vari=0;i<hosts.length;i++){varpropConfig=hosts[i];if(propConfig.name==up.analytics.host){propertyConfig=propConfig;break;}}if(propertyConfig!=null){console.info("[Analytics] Found property configuration for host:",up.analytics.host);returnpropertyConfig;}}console.info("[Analytics] Using default property configuration.");returnup.analytics.model.defaultConfig;};/** * Sets global settings from the property configuration. * @param {Object} propertyConfig - The property configuration object. */varconfigureDefaults=function(propertyConfig){vardefaults=propertyConfig.config||[];defaults.forEach(function(setting){Object.keys(setting).forEach(function(key){up.gtag('set',key,setting[key]);});});};/** * Retrieves dimensions that apply to the current user. * @param {Object} propertyConfig - The property configuration object. * @returns {Object} An object containing dimension key-value pairs. */vargetDimensions=function(propertyConfig){vardimensions={};vardimensionGroups=propertyConfig.dimensionGroups||[];dimensionGroups.forEach(function(setting){dimensions['dimension'+setting.name]=setting.value;});console.info("[Analytics] Dimensions set:",dimensions);returndimensions;};/** * Creates the Google Analytics tracker with the specified property ID and configuration. * @param {Object} propertyConfig - The property configuration object. */varcreateTracker=function(propertyConfig){varcreateSettings={};varconfigSettings=propertyConfig.config||[];configSettings.forEach(function(setting){if(setting.name!='name'){createSettings[setting.name]=setting.value;}});up.gtag('config',propertyConfig.propertyId,{send_page_view: false,});console.info("[Analytics] Tracker created with property ID:",propertyConfig.propertyId);};/** * Builds the page URI for a tab. * @param {string} [fragmentName] - The fragment name. * @param {string} [tabName] - The tab name. * @returns {string} The constructed tab URI. */vargetTabUri=function(fragmentName,tabName){if(up.analytics.pageData.tab!=null){fragmentName=fragmentName||up.analytics.pageData.tab.fragmentName;tabName=tabName||up.analytics.pageData.tab.tabName;}varuri='/';if(fragmentName!=null){uri+='tab/'+fragmentName;if(tabName!=null){uri+='/'+tabName;}}returnuri;};/** * Retrieves variables specific to the current page. * @param {string} [fragmentName] - The fragment name. * @param {string} [tabName] - The tab name. * @returns {Object} An object containing page variables. */vargetPageVariables=function(fragmentName,tabName){if(up.analytics.pageData.tab!=null){fragmentName=fragmentName||up.analytics.pageData.tab.fragmentName;tabName=tabName||up.analytics.pageData.tab.tabName;}vartitle;if(tabName!=null){title='Tab: '+tabName;}elseif(up.analytics.pageData.urlState==null){title='Portal Home';}else{title='No Tab';}return{page_location: getTabUri(fragmentName,tabName),page_title: title,};};/** * Safely resolves the portlet's fname from the windowId. * Falls back to using the windowId if no fname is found. * @param {string} windowId - The window ID of the portlet. * @returns {string} The fname of the portlet. */vargetPortletFname=function(windowId){varportletData=up.analytics.portletData[windowId];if(portletData==null){returnwindowId;}returnportletData.fname;};/** * Safely resolves the portlet's title from the windowId. * Falls back to using getPortletFname(windowId) if the title can't be found. * @param {string} windowId - The window ID of the portlet. * @returns {string} The title of the portlet. */vargetRenderedPortletTitle=function(windowId){varportletWindowWrapper=$('div.up-portlet-windowId-content-wrapper.'+windowId);if(portletWindowWrapper.length==0){returngetPortletFname(windowId);}varportletWrapper=portletWindowWrapper.parents('div.up-portlet-wrapper-inner');if(portletWrapper.length==0){returngetPortletFname(windowId);}varportletTitle=portletWrapper.find('div.up-portlet-titlebar h2 a');if(portletTitle.length==0){returngetPortletFname(windowId);}returnportletTitle.text().trim();};/** * Builds the portlet URI for the specified portlet. * @param {string} fname - The fname of the portlet. * @returns {string} The constructed portlet URI. */vargetPortletUri=function(fname){return'/portlet/'+fname;};/** * Retrieves variables specific to the specified portlet. * @param {string} windowId - The window ID of the portlet. * @param {Object} [portletData] - The data object of the portlet. * @returns {Object} An object containing portlet variables. */vargetPortletVariables=function(windowId,portletData){varportletTitle=getRenderedPortletTitle(windowId);if(portletData==null){portletData=up.analytics.portletData[windowId];}return{page_title: 'Portlet: '+portletTitle,page_location: getPortletUri(portletData.fname),};};/** * Retrieves the first class name from an element that is not in the excludedClasses array. * @param {Function} selectorFunction - A function that returns a jQuery element. * @param {string|string[]} excludedClasses - Class name or array of class names to exclude. * @returns {string|null} The first class name not in excludedClasses, or null if none found. */vargetInfoClass=function(selectorFunction,excludedClasses){// Ensure excludedClasses is an arrayif(!Array.isArray(excludedClasses)){excludedClasses=[excludedClasses];}varclassAttribute=selectorFunction().attr('class');if(classAttribute==null){returnnull;}varclasses=classAttribute.split(/\s+/);for(vari=0;i<classes.length;i++){varcls=classes[i];if(excludedClasses.indexOf(cls)===-1){returncls;}}returnnull;};/** * Determines the fname of the portlet the clicked flyout was rendered for. * @param {Object} clickedLink - The jQuery object representing the clicked link. * @returns {string|null} The fname of the portlet, or null if not found. */vargetFlyoutFname=function(clickedLink){returngetInfoClass(function(){returnclickedLink.parents('div.up-portlet-fname-subnav-wrapper');},'up-portlet-fname-subnav-wrapper');};/** * Determines the windowId of the portlet the clicked external link was rendered for. * @param {Object} clickedLink - The jQuery object representing the clicked link. * @returns {string|null} The windowId of the portlet, or null if not found. */vargetExternalLinkWindowId=function(clickedLink){returngetInfoClass(function(){returnclickedLink.parents('div.up-portlet-windowId-content-wrapper');},'up-portlet-windowId-content-wrapper');};/** * Handles link click events for analytics tracking. * Sends an analytics event and manages navigation behavior. * @param {Object} event - The jQuery event object. * @param {Object} clickedLink - The jQuery object representing the clicked link. * @param {Object} eventOptions - Additional options for the analytics event. */varhandleLinkClickEvent=function(event,clickedLink,eventOptions){// Determine if the click will open in a new windowvarnewWindow=event.button==1||event.metaKey||event.ctrlKey||clickedLink.attr('target')!=null;varclickFunction;clickFunction=newWindow
? function(){}
: function(){document.location=clickedLink.attr('href');};up.gtag('event','page_view',$.extend({event_callback: clickFunction,},eventOptions));// If not opening a new window, prevent default behavior and set a fallbackif(!newWindow){// Fallback in case event_callback is not called promptlysetTimeout(clickFunction,200);event.preventDefault();}};/** * Adds click handlers to flyout menus to fire analytics events when used. */varaddFlyoutHandlers=function(){$('ul.fl-tabs li.portal-navigation a.portal-subnav-link').click(function(event){varclickedLink=$(this);// Get the target portlet's titlevarportletFlyoutTitle=clickedLink.find('span.portal-subnav-label').text();// Get the target portlet's fnamevarfname=getFlyoutFname(clickedLink);// Setup page-level variablesvarpageVariables=getPageVariables();// Send the analytics event and handle the clickhandleLinkClickEvent(event,clickedLink,$.extend({event_category: 'Flyout Link',event_action: getPortletUri(fname),event_label: portletFlyoutTitle,},pageVariables));});};/** * Adds handlers to inspect clicks on links and track outbound link events. */varaddExternalLinkHandlers=function(){$('a').click(function(event){varclickedLink=$(this);varlinkHost=clickedLink.prop('hostname');if(linkHost!=''&&linkHost!=document.domain){varwindowId=getExternalLinkWindowId(clickedLink);vareventVariables=null;eventVariables=windowId==null
? getPageVariables()
: getPortletVariables(windowId);// Send the analytics event and handle the clickhandleLinkClickEvent(event,clickedLink,$.extend({event_category: 'Outbound Link',event_action: clickedLink.prop('href'),event_label: clickedLink.text(),},eventVariables));}});};/** * Adds handlers to track "tab" clicks in the mobile accordion view. */varaddMobileListTabHandlers=function(){$('ul.up-portal-nav li.up-tab').click(function(){varclickedTab=$(this);// Ignore clicks on already open tabsif(clickedTab.hasClass('up-tab-open')){return;}varfragmentName=getInfoClass(function(){returnclickedTab.find('div.up-tab-owner');},'up-tab-owner');vartabName=clickedTab.find('span.up-tab-name').text().trim();varpageVariables=getPageVariables(fragmentName,tabName);up.gtag('event','page_view',pageVariables);});};$(document).ready(function(){// Initialize property configurationvarpropertyConfig=findPropertyConfig();// No property config means analytics cannot proceedif(propertyConfig==null){console.error("[Analytics] No property configuration found. Analytics will not be initialized.");return;}// Set default configurationconfigureDefaults(propertyConfig);// Create the trackercreateTracker(propertyConfig);// Set dimensions for the current uservardimensions=getDimensions(propertyConfig);up.gtag('event','page_view',dimensions);// Prepare page-level variablesvarpageVariables=getPageVariables();// Send page view event unless in MAX WindowStateif(up.analytics.pageData.urlState!='MAX'){up.gtag('event','page_view',$.extend(pageVariables,dimensions));}// Send timing event for page loadup.gtag('event','timing_complete',$.extend({event_category: 'tab',name: getTabUri(),value: up.analytics.pageData.executionTimeNano,},pageVariables,dimensions));// Send events for each portletfor(varwindowIdinup.analytics.portletData){if(up.analytics.portletData.hasOwnProperty(windowId)){varportletData=up.analytics.portletData[windowId];// Skip excluded portletsif(portletData.fname=='google-analytics-config'){console.info("[Analytics] Skipping portlet:",portletData.fname);continue;}varportletVariables=getPortletVariables(windowId,portletData);up.gtag('event','page_view',portletVariables);up.gtag('event','timing_complete',$.extend({event_category: 'tab',name: getTabUri(),value: up.analytics.pageData.executionTimeNano,},portletVariables,dimensions));}}// Add event handlersaddFlyoutHandlers();addExternalLinkHandlers();addMobileListTabHandlers();});})(jQuery);
Maybe adding some around the null checks to let adopters know configuration may be missing, and info at some key points?
Also if this is an area we expect adopters to review more, we could also beef up the JSDocs a bit to give more context.
Originally posted by @ChristianMurphy in #2849 (comment)
The text was updated successfully, but these errors were encountered: