Skip to content

Commit 5cd9914

Browse files
committed
Refactor config handling in scripts.js to utilize new root path functions and enhance link decoration logic. Introduced async config retrieval and improved error handling for localized links.
1 parent a27262e commit 5cd9914

File tree

3 files changed

+133
-101
lines changed

3 files changed

+133
-101
lines changed

blocks/fragment/fragment.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
/**
1515
* Loads a fragment.
1616
* @param {string} path The path to the fragment
17-
* @returns {HTMLElement} The root element of the fragment
17+
* @returns {Promise<HTMLElement>} The root element of the fragment
1818
*/
1919
export async function loadFragment(path) {
2020
if (path && path.startsWith('/')) {

scripts/configs.js

Lines changed: 97 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
/* eslint-disable import/no-cycle */
22
import { deepmerge } from '@dropins/tools/lib.js';
33

4-
let AEM_ROOT_PATH = '/';
4+
// load config
5+
const CONFIG = await getConfig();
6+
const ROOT_PATH = getRootPath();
7+
const ROOT_CONFIG = await applyConfigOverrides(CONFIG, ROOT_PATH);
58

69
/**
710
* Builds the URL for the config file.
@@ -29,13 +32,98 @@ function getValue(obj, key) {
2932
}, obj);
3033
}
3134

35+
/**
36+
* Get root path
37+
* @param {Object} [config] - The config object.
38+
* @returns {string} - The root path.
39+
*/
40+
export function getRootPath() {
41+
const value = Object.keys(CONFIG?.public)
42+
// Sort by number of non-empty segments to find the deepest path
43+
.sort((a, b) => {
44+
const aSegments = a.split('/').filter(Boolean).length;
45+
const bSegments = b.split('/').filter(Boolean).length;
46+
return bSegments - aSegments;
47+
})
48+
.find((key) => window.location.pathname === key || window.location.pathname.startsWith(key));
49+
50+
const rootPath = value ?? '/';
51+
52+
if (!rootPath.startsWith('/') || !rootPath.endsWith('/')) {
53+
throw new Error('Invalid root path');
54+
}
55+
56+
return rootPath;
57+
}
58+
59+
/**
60+
* Get list of root paths from public config
61+
* @returns {Array} - The list of root paths.
62+
*/
63+
export function getListOfRootPaths() {
64+
return Object.keys(CONFIG?.public).filter((root) => root !== 'default');
65+
}
66+
67+
/**
68+
* Checks if the public config contains more than "default"
69+
* @returns true if public config contains more than "default"
70+
*/
71+
export function isMultistore() {
72+
return getListOfRootPaths().length > 1;
73+
}
74+
75+
/**
76+
* Retrieves a configuration value.
77+
*
78+
* @param {string} configParam - The configuration parameter to retrieve.
79+
* @returns {Promise<string|undefined>} - The value of the configuration parameter, or undefined.
80+
*/
81+
export async function getConfigValue(configParam) {
82+
return getValue(ROOT_CONFIG, configParam);
83+
}
84+
85+
/**
86+
* Retrieves headers from config entries like commerce.headers.pdp.my-header, etc and
87+
* returns as object of all headers like { my-header: value, ... }
88+
*/
89+
export async function getHeaders(scope) {
90+
const headers = ROOT_CONFIG.headers ?? {};
91+
return {
92+
...headers.all ?? {},
93+
...headers[scope] ?? {},
94+
};
95+
}
96+
97+
/**
98+
* Get cookie
99+
* @param {string} cookieName - The name of the cookie to get
100+
* @returns {string} - The value of the cookie
101+
*/
102+
export function getCookie(cookieName) {
103+
const cookies = document.cookie.split(';');
104+
let foundValue;
105+
106+
cookies.forEach((cookie) => {
107+
const [name, value] = cookie.trim().split('=');
108+
if (name === cookieName) {
109+
foundValue = decodeURIComponent(value);
110+
}
111+
});
112+
113+
return foundValue;
114+
}
115+
116+
export function checkIsAuthenticated() {
117+
return !!getCookie('auth_dropin_user_token') ?? false;
118+
}
119+
32120
/**
33121
* Fetches config from remote and saves in session, then returns it, otherwise
34122
* returns if it already exists.
35123
*
36-
* @returns the config JSON from session storage
124+
* @returns {Promise<Object>} - The config JSON from session storage
37125
*/
38-
const getConfigFromSession = async () => {
126+
async function getConfigFromSession() {
39127
try {
40128
const configJSON = window.sessionStorage.getItem('config');
41129
if (!configJSON) {
@@ -57,37 +145,6 @@ const getConfigFromSession = async () => {
57145
window.sessionStorage.setItem('config', JSON.stringify(configJSON));
58146
return configJSON;
59147
}
60-
};
61-
62-
/**
63-
* Retrieves the commerce config.
64-
*
65-
* @returns {Promise<Object>} - The commerce config.
66-
*/
67-
let configCache;
68-
const getConfig = async () => {
69-
if (!configCache) {
70-
// Only fetch if not already cached
71-
const result = await applyConfigOverrides(await getConfigFromSession());
72-
configCache = result;
73-
}
74-
return configCache;
75-
};
76-
77-
/**
78-
* Get root path
79-
*/
80-
export function getRootPath() {
81-
return AEM_ROOT_PATH ?? '/';
82-
}
83-
84-
/**
85-
*
86-
* @returns true if public config contains more than "default"
87-
*/
88-
export async function isMultistore() {
89-
const config = await getConfigFromSession();
90-
return Object.keys(config.public).filter((root) => root !== 'default').length > 0;
91148
}
92149

93150
/**
@@ -96,24 +153,7 @@ export async function isMultistore() {
96153
* @param {Object} config - The base config.
97154
* @returns {Object} - The config with overrides applied.
98155
*/
99-
async function applyConfigOverrides(config) {
100-
const root = Object.keys(config.public)
101-
// Sort by number of non-empty segments to find the deepest path
102-
.sort((a, b) => {
103-
const aSegments = a.split('/').filter(Boolean).length;
104-
const bSegments = b.split('/').filter(Boolean).length;
105-
return bSegments - aSegments;
106-
})
107-
.find((key) => window.location.pathname === key || window.location.pathname.startsWith(key));
108-
109-
const rootPath = root ?? '/';
110-
111-
if (!rootPath.startsWith('/') || !rootPath.endsWith('/')) {
112-
throw new Error('Invalid root path');
113-
}
114-
115-
AEM_ROOT_PATH = rootPath;
116-
156+
async function applyConfigOverrides(config, root) {
117157
const defaultConfig = config.public?.default;
118158

119159
if (!defaultConfig) {
@@ -129,41 +169,10 @@ async function applyConfigOverrides(config) {
129169
}
130170

131171
/**
132-
* This function retrieves a configuration value.
172+
* Retrieves the commerce config.
133173
*
134-
* @param {string} configParam - The configuration parameter to retrieve.
135-
* @returns {Promise<string|undefined>} - The value of the configuration parameter, or undefined.
136-
*/
137-
export const getConfigValue = async (configParam) => {
138-
const config = await getConfig();
139-
return getValue(config, configParam);
140-
};
141-
142-
/**
143-
* Retrieves headers from config entries like commerce.headers.pdp.my-header, etc and
144-
* returns as object of all headers like { my-header: value, ... }
174+
* @returns {Promise<Object>} - The commerce config.
145175
*/
146-
export const getHeaders = async (scope) => {
147-
const config = await getConfig();
148-
const headers = config.headers ?? {};
149-
return {
150-
...headers.all ?? {},
151-
...headers[scope] ?? {},
152-
};
153-
};
154-
155-
export const getCookie = (cookieName) => {
156-
const cookies = document.cookie.split(';');
157-
let foundValue;
158-
159-
cookies.forEach((cookie) => {
160-
const [name, value] = cookie.trim().split('=');
161-
if (name === cookieName) {
162-
foundValue = decodeURIComponent(value);
163-
}
164-
});
165-
166-
return foundValue;
167-
};
168-
169-
export const checkIsAuthenticated = () => !!getCookie('auth_dropin_user_token') ?? false;
176+
async function getConfig() {
177+
return getConfigFromSession();
178+
}

scripts/scripts.js

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
import { trackHistory } from './commerce.js';
2525
import initializeDropins from './initializers/index.js';
2626
import { removeHashTags } from './api/hashtags/parser.js';
27-
import { getRootPath } from './configs.js';
27+
import { getRootPath, getListOfRootPaths } from './configs.js';
2828

2929
const AUDIENCES = {
3030
mobile: () => window.innerWidth < 600,
@@ -161,7 +161,7 @@ function notifyUI(event) {
161161
*/
162162
// eslint-disable-next-line import/prefer-default-export
163163
export function decorateMain(main) {
164-
// hopefully forward compatible button decoration
164+
decorateLinks(main);
165165
decorateButtons(main);
166166
decorateIcons(main);
167167
buildAutoBlocks(main);
@@ -172,16 +172,40 @@ export function decorateMain(main) {
172172
/**
173173
* Decorates all links in scope of element
174174
*
175-
* @param {HTMLElement} element
175+
* @param {HTMLElement} main
176176
*/
177-
function decorateLinks(element) {
178-
element.querySelectorAll('a').forEach((a) => {
179-
if (!a.hash) {
180-
return;
177+
function decorateLinks(main) {
178+
const root = getRootPath();
179+
const roots = getListOfRootPaths();
180+
181+
main.querySelectorAll('a').forEach((a) => {
182+
if (a.hash) {
183+
a.addEventListener('click', (evt) => {
184+
removeHashTags(evt.target);
185+
});
186+
}
187+
188+
// If we are in the root, do nothing
189+
if (roots.length === 0) return;
190+
191+
try {
192+
const url = new URL(a.href);
193+
const {
194+
origin,
195+
pathname,
196+
search,
197+
hash,
198+
} = url;
199+
200+
// if the links belongs to another store, do nothing
201+
if (roots.some((r) => r !== root && pathname.startsWith(r))) return;
202+
203+
// If the link is already localized, do nothing
204+
if (origin !== window.location.origin || pathname.startsWith(root)) return;
205+
a.href = new URL(`${origin}${root}${pathname.replace(/^\//, '')}${search}${hash}`);
206+
} catch {
207+
console.warn('Could not make localized link');
181208
}
182-
a.addEventListener('click', (evt) => {
183-
removeHashTags(evt.target);
184-
});
185209
});
186210
}
187211

@@ -339,8 +363,6 @@ async function loadLazy(doc) {
339363
}
340364
loadCSS(`${window.hlx.codeBasePath}/styles/lazy-styles.css`);
341365
loadFonts();
342-
343-
decorateLinks(doc);
344366
}
345367

346368
/**
@@ -395,6 +417,7 @@ export async function fetchIndex(indexFile, pageSize = 500) {
395417
/**
396418
* Decorates links.
397419
* @param {string} [link] url to be localized
420+
* @returns {string} - The localized link
398421
*/
399422
export function rootLink(link) {
400423
const root = getRootPath().replace(/\/$/, '');

0 commit comments

Comments
 (0)