From 2c4712aab6ee1d439cbedf939bec7d882e65e46f Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Wed, 17 May 2023 20:04:57 +0200 Subject: [PATCH 1/2] MWPW-126707: Global navigation lana logs --- .../features/profile/dropdown.js | 4 +- .../features/search/gnav-search.js | 3 +- .../global-navigation/global-navigation.js | 86 +++++++++---------- .../utilities/keyboard/index.js | 15 ++-- .../utilities/keyboard/mainNav.js | 6 +- .../utilities/keyboard/mobilePopup.js | 6 +- .../utilities/keyboard/popup.js | 6 +- .../global-navigation/utilities/menu/menu.js | 5 +- .../global-navigation/utilities/utilities.js | 42 ++++++--- 9 files changed, 98 insertions(+), 75 deletions(-) diff --git a/libs/blocks/global-navigation/features/profile/dropdown.js b/libs/blocks/global-navigation/features/profile/dropdown.js index d6f0a19ee0..4dca463241 100644 --- a/libs/blocks/global-navigation/features/profile/dropdown.js +++ b/libs/blocks/global-navigation/features/profile/dropdown.js @@ -1,5 +1,5 @@ import { getConfig } from '../../../../utils/utils.js'; -import { toFragment, getFedsPlaceholderConfig, trigger, closeAllDropdowns } from '../../utilities/utilities.js'; +import { toFragment, getFedsPlaceholderConfig, trigger, closeAllDropdowns, logErrorFor } from '../../utilities/utilities.js'; import { replaceKeyArray } from '../../../../features/placeholders.js'; const getLanguage = (ietfLocale) => { @@ -54,7 +54,7 @@ class ProfileDropdown { this.sections = sections; this.openOnInit = openOnInit; this.localMenu = rawElem.querySelector('h5')?.parentElement; - this.init(); + logErrorFor(this.init.bind(this), 'ProfileDropdown.init()'); } async init() { diff --git a/libs/blocks/global-navigation/features/search/gnav-search.js b/libs/blocks/global-navigation/features/search/gnav-search.js index 38a886116a..6d5980cec3 100644 --- a/libs/blocks/global-navigation/features/search/gnav-search.js +++ b/libs/blocks/global-navigation/features/search/gnav-search.js @@ -3,6 +3,7 @@ import { getFedsPlaceholderConfig, trigger, closeAllDropdowns, + logErrorFor, } from '../../utilities/utilities.js'; import { replaceKeyArray } from '../../../../features/placeholders.js'; import { getConfig } from '../../../../utils/utils.js'; @@ -43,7 +44,7 @@ class Search { this.clearSearchForm(); }); observer.observe(this.trigger, { attributeFilter: ['aria-expanded'] }); - this.init(); + logErrorFor(this.init.bind(this), 'Search has failed loading'); } async init() { diff --git a/libs/blocks/global-navigation/global-navigation.js b/libs/blocks/global-navigation/global-navigation.js index cc848b111b..6071eb176f 100644 --- a/libs/blocks/global-navigation/global-navigation.js +++ b/libs/blocks/global-navigation/global-navigation.js @@ -20,6 +20,8 @@ import { loadBaseStyles, yieldToMain, selectors, + logErrorFor, + lanaLog, } from './utilities/utilities.js'; import { replaceKey } from '../../features/placeholders.js'; @@ -37,14 +39,6 @@ const CONFIG = { }, }; -function getBlockClasses(className) { - const trimDashes = (str) => str.replace(/(^\s*-)|(-\s*$)/g, ''); - const blockWithVariants = className.split('--'); - const name = trimDashes(blockWithVariants.shift()); - const variants = blockWithVariants.map((v) => trimDashes(v)); - return { name, variants }; -} - // signIn, decorateSignIn and decorateProfileTrigger can be removed if IMS takes over the profile const signIn = () => { if (typeof window.adobeIMS?.signIn !== 'function') return; @@ -145,13 +139,9 @@ class Gnav { this.body = body; this.isDesktop = window.matchMedia('(min-width: 900px)'); this.elements = {}; - body.querySelectorAll('[class$="-"]').forEach((block) => { - const { name, variants } = getBlockClasses(block.className); - block.classList.add(name, ...variants); - }); } - init = async () => { + init = () => logErrorFor(async () => { this.elements.curtain = toFragment`
`; // Order is important, decorateTopnavWrapper will render the nav @@ -174,7 +164,7 @@ class Gnav { } document.addEventListener('click', closeOnClickOutside); - }; + }, 'Error in global navigation init'); decorateTopNav = () => { this.elements.mobileToggle = this.mobileToggle(); @@ -233,23 +223,28 @@ class Gnav { loadDelayed = async () => { this.ready = this.ready || new Promise(async (resolve) => { - this.el.removeEventListener('click', this.loadDelayed); - this.el.removeEventListener('keydown', this.loadDelayed); - const [ - { appLauncher }, - ProfileDropdown, - Search, - ] = await Promise.all([ - loadBlock('../features/appLauncher/appLauncher.js'), - loadBlock('../features/profile/dropdown.js'), - loadBlock('../features/search/gnav-search.js'), - loadStyles('features/profile/dropdown.css'), - loadStyles('features/search/gnav-search.css'), - ]); - this.ProfileDropdown = ProfileDropdown; - this.appLauncher = appLauncher; - this.Search = Search; - resolve(); + try { + this.el.removeEventListener('click', this.loadDelayed); + this.el.removeEventListener('keydown', this.loadDelayed); + const [ + { appLauncher }, + ProfileDropdown, + Search, + ] = await Promise.all([ + loadBlock('../features/appLauncher/appLauncher.js'), + loadBlock('../features/profile/dropdown.js'), + loadBlock('../features/search/gnav-search.js'), + loadStyles('features/profile/dropdown.css'), + loadStyles('features/search/gnav-search.css'), + ]); + this.ProfileDropdown = ProfileDropdown; + this.appLauncher = appLauncher; + this.Search = Search; + resolve(); + } catch (e) { + lanaLog({ message: 'Error within loadDelayed', e }); + resolve(); + } }); return this.ready; @@ -270,9 +265,13 @@ class Gnav { this.decorateProfile, this.decorateAppLauncher, ]; - for await (const task of tasks) { - await yieldToMain(); - await task(); + try { + for await (const task of tasks) { + await yieldToMain(); + await task(); + } + } catch (e) { + lanaLog({ message: 'Global Navigation, issues within onReady', e }); } }, }; @@ -291,7 +290,7 @@ class Gnav { // If user is not signed in, decorate the 'Sign In' element if (!isSignedInUser) { - decorateSignIn({ rawElem, decoratedElem }); + await decorateSignIn({ rawElem, decoratedElem }); return; } @@ -374,11 +373,9 @@ class Gnav { } }; - this.isDesktop.addEventListener('change', () => { - setHamburgerPadding(); - }); + this.isDesktop.addEventListener('change', () => logErrorFor(setHamburgerPadding, 'Set hamburger padding failed')); - toggle.addEventListener('click', async () => { + const toggleClick = async () => { if (this.el.classList.contains(CONFIG.selectors.isOpen)) { this.el.classList.remove(CONFIG.selectors.isOpen); this.elements.curtain.classList.remove(CONFIG.selectors.isOpen); @@ -396,7 +393,9 @@ class Gnav { setHamburgerPadding(); } - }); + }; + + toggle.addEventListener('click', () => logErrorFor(toggleClick, 'Toggle click failed')); return toggle; }; @@ -483,7 +482,7 @@ class Gnav { const delayDropdownDecoration = (template) => { let decorationTimeout; - const decorateDropdown = async () => { + const decorateDropdown = () => logErrorFor(async () => { template.removeEventListener('click', decorateDropdown); clearTimeout(decorationTimeout); @@ -494,7 +493,7 @@ class Gnav { template, type: itemType, }); - }; + }, 'Decorate dropdown failed'); template.addEventListener('click', decorateDropdown); decorationTimeout = setTimeout(decorateDropdown, CONFIG.delays.mainNavDropdowns); @@ -641,8 +640,7 @@ export default async function init(header) { header.setAttribute('daa-lh', `gnav|${getExperienceName()}`); return gnav; } catch (e) { - // eslint-disable-next-line no-console - console.log('Could not create global navigation:', e); + lanaLog({ message: 'Could not create global navigation.', e }); return null; } } diff --git a/libs/blocks/global-navigation/utilities/keyboard/index.js b/libs/blocks/global-navigation/utilities/keyboard/index.js index a66a41eca2..94de97e283 100644 --- a/libs/blocks/global-navigation/utilities/keyboard/index.js +++ b/libs/blocks/global-navigation/utilities/keyboard/index.js @@ -1,6 +1,7 @@ /* eslint-disable class-methods-use-this */ import { getNextVisibleItemPosition, getPreviousVisibleItemPosition, selectors } from './utils.js'; import MainNav from './mainNav.js'; +import { lanaLog, logErrorFor } from '../utilities.js'; const cycleOnOpenSearch = ({ e, isDesktop }) => { const withoutBreadcrumbs = [ @@ -26,13 +27,17 @@ const cycleOnOpenSearch = ({ e, isDesktop }) => { class KeyboardNavigation { constructor() { - this.addEventListeners(); - this.mainNav = new MainNav(); - this.desktop = window.matchMedia('(min-width: 900px)'); + try { + this.addEventListeners(); + this.mainNav = new MainNav(); + this.desktop = window.matchMedia('(min-width: 900px)'); + } catch (e) { + lanaLog({ message: 'Keyboard Navigation failed to load', e }); + } } addEventListeners = () => { - document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => { + document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => logErrorFor(() => { switch (e.code) { case 'Tab': { cycleOnOpenSearch({ e, isDesktop: this.desktop.matches }); @@ -55,7 +60,7 @@ class KeyboardNavigation { default: break; } - }); + }, `KeyboardNavigation index failed. ${e.code}`)); }; } diff --git a/libs/blocks/global-navigation/utilities/keyboard/mainNav.js b/libs/blocks/global-navigation/utilities/keyboard/mainNav.js index 6791e4ddaa..6d4995a3bb 100644 --- a/libs/blocks/global-navigation/utilities/keyboard/mainNav.js +++ b/libs/blocks/global-navigation/utilities/keyboard/mainNav.js @@ -2,7 +2,7 @@ import { selectors, getNextVisibleItemPosition, getPreviousVisibleItemPosition } from './utils.js'; import Popup from './popup.js'; import MobilePopup from './mobilePopup.js'; -import { closeAllDropdowns, trigger } from '../utilities.js'; +import { closeAllDropdowns, trigger, logErrorFor } from '../utilities.js'; class MainNavItem { constructor() { @@ -14,7 +14,7 @@ class MainNavItem { addEventListeners() { document.querySelector(selectors.globalNav) - .addEventListener('keydown', (e) => { + .addEventListener('keydown', (e) => logErrorFor(() => { if (!e.target.closest(selectors.fedsNav) || e.target.closest(selectors.popup)) { return; } @@ -82,7 +82,7 @@ class MainNavItem { default: break; } - }); + }, `mainNav key failed ${e.code}`)); } setActive = (target) => { diff --git a/libs/blocks/global-navigation/utilities/keyboard/mobilePopup.js b/libs/blocks/global-navigation/utilities/keyboard/mobilePopup.js index d0d0ca3127..fed4e9dbc3 100644 --- a/libs/blocks/global-navigation/utilities/keyboard/mobilePopup.js +++ b/libs/blocks/global-navigation/utilities/keyboard/mobilePopup.js @@ -6,7 +6,7 @@ import { getOpenPopup, selectors, } from './utils.js'; -import { closeAllDropdowns } from '../utilities.js'; +import { closeAllDropdowns, logErrorFor } from '../utilities.js'; const closeHeadlines = () => { const open = [...document.querySelectorAll(`${selectors.headline}[aria-expanded="true"]`)]; @@ -122,7 +122,7 @@ class Popup { }; addEventListeners = () => { - document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => { + document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => logErrorFor(() => { const popupEl = getOpenPopup(); if (!e.target.closest(selectors.popup) || !popupEl || this.desktop.matches) return; e.preventDefault(); @@ -189,7 +189,7 @@ class Popup { default: break; } - }); + }, `mobile popup key failed ${e.code}`)); }; } diff --git a/libs/blocks/global-navigation/utilities/keyboard/popup.js b/libs/blocks/global-navigation/utilities/keyboard/popup.js index 3bf2e92c5b..eafdcd6704 100644 --- a/libs/blocks/global-navigation/utilities/keyboard/popup.js +++ b/libs/blocks/global-navigation/utilities/keyboard/popup.js @@ -5,7 +5,7 @@ import { getOpenPopup, selectors, } from './utils.js'; -import { closeAllDropdowns } from '../utilities.js'; +import { closeAllDropdowns, logErrorFor } from '../utilities.js'; const getState = ({ e } = {}) => { const popupEl = getOpenPopup(); @@ -46,7 +46,7 @@ class Popup { } addEventListeners = () => { - document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => { + document.querySelector(selectors.globalNav).addEventListener('keydown', (e) => logErrorFor(() => { const popupEl = getOpenPopup(); if (!e.target.closest(selectors.popup) || !popupEl || !this.desktop.matches) return; e.preventDefault(); @@ -125,7 +125,7 @@ class Popup { default: break; } - }); + }, `popup key failed ${e.code}`)); }; } diff --git a/libs/blocks/global-navigation/utilities/menu/menu.js b/libs/blocks/global-navigation/utilities/menu/menu.js index c94ed5b623..8765c6e1ed 100644 --- a/libs/blocks/global-navigation/utilities/menu/menu.js +++ b/libs/blocks/global-navigation/utilities/menu/menu.js @@ -5,6 +5,7 @@ import { decorateCta, yieldToMain, getFedsPlaceholderConfig, + logErrorFor, } from '../utilities.js'; import { decorateLinks } from '../../../../utils/utils.js'; import { replaceText } from '../../../../features/placeholders.js'; @@ -246,7 +247,7 @@ const decorateColumns = async ({ content, separatorTagName = 'H5' } = {}) => { // Current limitation: after an h5 (or h2 in the case of the footer) // is found in a menu column, no new sections can be created without a heading -const decorateMenu = async (config) => { +const decorateMenu = (config) => logErrorFor(async () => { let menuTemplate; if (config.type === 'syncDropdownTrigger') { @@ -287,6 +288,6 @@ const decorateMenu = async (config) => { } config.template?.append(menuTemplate); -}; +}, 'Decorate menu failed'); export default { decorateMenu, decorateLinkGroup }; diff --git a/libs/blocks/global-navigation/utilities/utilities.js b/libs/blocks/global-navigation/utilities/utilities.js index 06fa2f99a6..b7b55dfb7b 100644 --- a/libs/blocks/global-navigation/utilities/utilities.js +++ b/libs/blocks/global-navigation/utilities/utilities.js @@ -1,4 +1,6 @@ -import { getConfig, getMetadata, loadStyle } from '../../../utils/utils.js'; +import { getConfig, getMetadata, loadStyle, loadLana } from '../../../utils/utils.js'; + +loadLana(); export const selectors = { globalNav: '.global-navigation', @@ -83,19 +85,22 @@ export function loadBlock(path) { let cachedDecorateMenu; export async function loadDecorateMenu() { - // eslint-disable-next-line no-async-promise-executor - cachedDecorateMenu = cachedDecorateMenu || new Promise(async (resolve) => { - const [{ decorateMenu, decorateLinkGroup }] = await Promise.all([ - loadBlock('./menu/menu.js'), - loadStyles('utilities/menu/menu.css'), - ]); - - resolve({ - decorateMenu, - decorateLinkGroup, - }); + if (cachedDecorateMenu) return cachedDecorateMenu; + + let resolve; + cachedDecorateMenu = cachedDecorateMenu || new Promise((_resolve) => { + resolve = _resolve; }); + const [{ decorateMenu, decorateLinkGroup }] = await Promise.all([ + loadBlock('./menu/menu.js'), + loadStyles('utilities/menu/menu.css'), + ]); + + resolve({ + decorateMenu, + decorateLinkGroup, + }); return cachedDecorateMenu; } @@ -153,3 +158,16 @@ export function expandTrigger({ element } = {}) { } export const yieldToMain = () => new Promise((resolve) => { setTimeout(resolve, 0); }); + +export const lanaLog = ({ message, e = '' }) => window.lana.log(`${message} ${e.reason || e.error || e.message || e}`, { + clientId: 'feds-milo', + sampleRate: 1, +}); + +export const logErrorFor = async (fn, message) => { + try { + await fn(); + } catch (e) { + lanaLog({ message, e }); + } +}; From 15c364c25be9c6d0f64c621884d5288b99b24063 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Mon, 22 May 2023 14:53:34 +0200 Subject: [PATCH 2/2] Address feedback --- libs/blocks/global-navigation/global-navigation.js | 4 ++-- libs/blocks/global-navigation/utilities/utilities.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/blocks/global-navigation/global-navigation.js b/libs/blocks/global-navigation/global-navigation.js index 6071eb176f..8d18d6dc70 100644 --- a/libs/blocks/global-navigation/global-navigation.js +++ b/libs/blocks/global-navigation/global-navigation.js @@ -242,7 +242,7 @@ class Gnav { this.Search = Search; resolve(); } catch (e) { - lanaLog({ message: 'Error within loadDelayed', e }); + lanaLog({ message: 'GNAV: Error within loadDelayed', e }); resolve(); } }); @@ -271,7 +271,7 @@ class Gnav { await task(); } } catch (e) { - lanaLog({ message: 'Global Navigation, issues within onReady', e }); + lanaLog({ message: 'GNAV: issues within onReady', e }); } }, }; diff --git a/libs/blocks/global-navigation/utilities/utilities.js b/libs/blocks/global-navigation/utilities/utilities.js index b7b55dfb7b..876c2cffe9 100644 --- a/libs/blocks/global-navigation/utilities/utilities.js +++ b/libs/blocks/global-navigation/utilities/utilities.js @@ -88,7 +88,7 @@ export async function loadDecorateMenu() { if (cachedDecorateMenu) return cachedDecorateMenu; let resolve; - cachedDecorateMenu = cachedDecorateMenu || new Promise((_resolve) => { + cachedDecorateMenu = new Promise((_resolve) => { resolve = _resolve; });