@douglas.onsite.experimentation/douglas-ab-testing-toolkit
v4.0.0
Published
DOUGLAS A/B Testing Toolkit
Readme
DOUGLAS A/B Testing Toolkit
Öffentliche Doku – keine internen URLs, Keys oder personenbezogenen Daten hier einfügen.
Inhalt
Detaillierte Signaturen und Parameter: JSDoc in douglas-toolkit.js. Nicht jedes Export ist unten einzeln ausgeschrieben (siehe API overview).
Getting started
This toolkit is designed to help you creating A/B tests. Have fun using it!
Questions or feedback? Max Vith [email protected] Kristina Bekher [email protected]
Install
Scoped package name (siehe package.json):
npm install @douglas.onsite.experimentation/douglas-ab-testing-toolkityarn add @douglas.onsite.experimentation/douglas-ab-testing-toolkitimport { elem, qs } from '@douglas.onsite.experimentation/douglas-ab-testing-toolkit';Usage Example
import { elem } from '@douglas.onsite.experimentation/douglas-ab-testing-toolkit';
elem('#example', (example) => {
// do something...
});Bundle size (production)
- Tree-Shaking: Immer benannte Imports nutzen (
import { qs, elem } from '…'), keinimport * as toolkit. Das Paket ist mit"sideEffects": falsemarkiert, damit Bundler ungenutzte Exports entfernen können. - Minify: Experiment-Build mit esbuild / Terser / swc minifizieren; optional
drop_consoleoder nur Debug-Logs streichen, wenn ihr in Prod keine Logs braucht. - Kameleoon-Rohscript: Wird das Toolkit ohne Bundler komplett eingebunden, gibt es kein Tree-Shaking – dann zählt die gesamte Datei. Dann: eigenes kleines Bundle nur mit den genutzten Imports bauen und eine minifizierte Datei in Kameleoon legen.
- Aufteilen (optional): Nur nötig, wenn ihr weiterhin das volle Monolit-Script ohne Bundler ausliefern müsst und trotzdem kleiner werden wollt – dann z. B. thematische Entry-Files +
package.jsonexports. console.error: Wenn ihr beidrop_consolealleconsole.*entfernt, betrifft das ggf. auch Fehlerausgaben auslogError– ggf. nurlog/info/debugstrippen.
Testing
Im Paketroot (nur für Entwicklung des Toolkits, nicht im npm-Tarball enthalten):
npm install
npm run test # Watch
npm run test:run # CI / einmaligTests liegen unter tests/. Lokale Fixtures mit sensiblen Daten: *.local.json (siehe tests/fixtures/README.md und .gitignore).
Best practices
- Imports: Benannte Imports, kein
import *– nutzt Tree-Shaking (sideEffects: false). - Globals: Viele Helfer nutzen
window(z. B.OE_TOOLKIT,OE_METRICS,System,Kameleoon) – vor Aufruf prüfen, ob die Umgebung (Shop + Kameleoon) passt. share/exec: Global JS registriert mitshare, Varianten-JS ruftexec(name, params); ausstehende Aufrufe werden in einer Queue gehalten und nachsharebzw.exec()ohne Name abgearbeitet.- Keine Secrets in Experiment-Code oder öffentlicher Doku; Ziel-IDs und URLs möglichst generisch halten.
API overview
Alle folgenden Symbole werden aus douglas-toolkit.js exportiert:
| Bereich | Exports |
|--------|---------|
| DOM / Warten | qs, qsa, elem, elemSync, addClass, removeClass, hasClass, toggleClass, addPrefix, removePrefix, setMutationObserver, setClickEvent, setAccessabilityEvents |
| Globals / Queue | share, exec, asyncSave |
| Kameleoon / Daten | pushMetric, pushData |
| Observer (Toolkit) | addTask, removeTask, updateConfig |
| Shop / URL | getState, getProdId, getProduct, getProducts, getPage, goTo, pageChange, pushHistory |
| Storage / Cookies | getCookie, setCookie, getStore, setStore |
| UI / Media | getWidth, isMobile, scrollTo, inViewport, isElementInViewport, setPreload, loadLibrary, addStyleToBody |
| Sonstiges | hotjar |
logError ist nicht exportiert (intern für asyncSave u. a.).
Helper Functions
elem
The elem function is using document.querySelector() internally.
The elem function continuously checks for the presence of DOM elements matching a specified CSS selector or evaluates a custom condition provided as a function. It executes a callback when the condition is met or times out after 10 seconds.
Parameters
- selector (string | function): A CSS selector string to query elements from the DOM. Alternatively, a function that evaluates to true when the desired condition is met.
- callback (function): A function called when either:
- Matching elements are found, and the result is passed as an argument.
- The timeout of 10 seconds is reached without finding any elements or satisfying the condition, in which case false is passed to the callback.
Behavior
- If selector is a string, it is converted into a function that queries elements using qsa(selector).
- The function iteratively checks for the presence of elements or evaluates the condition every 33 milliseconds.
- If elements are found or the condition returns a truthy value, the callback is invoked with the result.
- If no elements are found within the 10-second window, the callback is called with false.
Usage Example
elem('.my-class', elements => {
if (elements) {
console.log('Found elements:', elements);
} else {
console.log('No elements found within the timeout period.');
}
});Using a Custom Condition
elem(() => document.querySelector('#special-element') !== null, result => {
if (result) {
console.log('Special element is now available.');
} else {
console.log('Element not found within the timeout period.');
}
});Notes
- The timeout period is hard-coded to 10 seconds.
- The polling interval is 33 milliseconds.
elemSync
elemSync is an asynchronous function that waits for DOM elements to be available by utilizing a provided elem function. It returns a Promise that resolves with the elements matching the specified CSS selector.
Parameters
- selector (string): A CSS selector used to query the desired DOM elements.
Return Value
- Returns a Promise that resolves to: elements: The elements found by the elem function, based on the provided selector.
Usage Example
(async () => {
const elements = await elemSync(".my-class");
if(!elements) return;
console.log('Elements found:', elements);
})();elemSync('.my-class').then(elements => {
if (elements) {
console.log('Elements found:', elements);
} else {
console.log('No elements found.');
}
});Assumptions
The function assumes that elem is a pre-existing function that accepts a CSS selector and a callback, providing matched elements asynchronously.
Notes
- Über
elemwird bei Timeoutfalsean den Callback übergeben;elemSyncresolved entsprechend mitfalse.
share
Registriert eine benannte Funktion auf window.OE_TOOLKIT, typischerweise im Global Script (Kameleoon). Danach werden wartende exec-Einträge für bereits vorhandene Handler aus der Queue ausgeführt.
Parameters
- name (string): Schlüssel auf
window.OE_TOOLKIT. - func (function): Aufzurufende Implementierung.
Usage Example
share('myExperimentInit', (config) => {
// …
});Rückgabewert: window.OE_TOOLKIT.
exec
Ruft window.OE_TOOLKIT[name](params) auf, oder queued den Aufruf, bis share die Funktion registriert hat. exec() ohne Namen leert die Queue für alle Einträge, deren Handler bereits existieren.
Parameters
- name (string, optional): Handler-Name.
- params (any): Wird an den Handler übergeben.
Notes
- Mehrfaches
exec(name, …)vorshare: nur ein Queue-Eintrag proname; letzterparamsgewinnt. - Nach erfolgreichem direkten
execwerden Queue-Einträge für diesen Namen entfernt.
Usage Example
exec('myExperimentInit', { flag: true });
exec(); // Queue flushen, falls Handler schon registriert sindasyncSave
Wrap für async Funktionen: try/catch, Fehler werden intern per console.error (>>> OE_ERROR) geloggt. Standard: Fehler nicht erneut werfen.
Parameters
- fn (
Function): Async-Funktion. - prefix (
string, optional): Kontext für Logs. - options (optional):
{ rethrow: true }– nach Log den Fehler weiterwerfen.
Usage Example
const safe = asyncSave(async () => { /* … */ }, 'myExperiment', { rethrow: false });
await safe();pushMetric
You can use the pushMetric function for sending goals (unique and multiple).
The pushMetric function logs and optionally tracks unique conversion metrics during A/B testing experiments. It stores metric IDs in a global array (window.OE_METRICS) and provides placeholders for integrating with third-party analytics tools.
Parameters
- id (string): The identifier for the metric or goal to be tracked.
- unique (boolean) [optional]: If true, the function ensures the metric is only tracked once by checking if the id is already present in window.OE_METRICS. Defaults to false.
Usage Example
Track a Metric Once
pushMetric('goal_123', true);Tracks the metric with ID goal_123 only if it hasn’t been tracked before.
Track the Same Metric Multiple Times
pushMetric('goal_123');Allows repeated tracking of the same metric (mehrfache processConversion-Aufrufe möglich).
Notes
- Ruft
Kameleoon.API.Goals.processConversion(id)auf (Kameleoon muss auf der Seite verfügbar sein). - Fehler werden abgefangen und geloggt.
window.OE_METRICSmerkt sich bereits gesendete IDs (fürunique).
pushData
Setzt Custom Data über Kameleoon?.API?.Data?.setCustomData(key, value, options) (optional chaining – ohne Kameleoon keine Wirkung). Details siehe Kameleoon-Doku.
Wrapper Functions
qs
The qs function is just a wrapper for document.querySelector().
The qs function is a utility for selecting a single DOM element using a CSS selector. It simplifies element selection by optionally allowing searches within a specific parent element.
Parameters
- selector (string): A CSS selector string used to identify the desired element.
- parent (Element | Document) [Optional]: The element or document context within which the selector will be applied. Defaults to document if not provided.
Return Value
- Returns the first element within the specified parent that matches the given selector.
- If no matching element is found, it returns null.
Usage Example
const button = qs('.submit-button');
if (button) {
button.addEventListener('click', () => console.log('Button clicked!'));
}Selecting an element within a specific parent container
const container = document.getElementById('form-container');
const inputField = qs('input[name="username"]', container);
if (inputField) {
inputField.focus();
}qsa
The qsa function is just a wrapper for document.querySelectorAll().
The qsa function is a utility for selecting multiple DOM elements using a CSS selector. It allows querying within a specific parent element or the entire document.
Parameters
- selector (string): A CSS selector string used to identify the desired elements.
- parent (Element | Document) [Optional]: The element or document context within which the selector will be applied. Defaults to document if not provided.
Return Value
- Returns a NodeList containing all elements that match the given selector within the specified parent context.
- If no elements match, an empty NodeList is returned.
Usage Example
const buttons = qsa('.button-class');
buttons.forEach(button => {
button.addEventListener('click', () => console.log('Button clicked!'));
});Selecting elements within a specific parent container
const container = document.getElementById('nav-container');
const links = qsa('a', container);
links.forEach(link => {
console.log('Link text:', link.textContent);
});addClass
The addClass function adds a specified CSS class to a given HTML element if the class is not already present. It ensures that the operation only proceeds when the element and class name are valid.
Parameters
- element (HTMLElement): The target HTML element to which the class should be added.
- selector (string): The CSS class name to add to the element.
Return Value
- Returns true if the class is successfully added.
- Returns undefined if the operation is not performed due to missing or invalid input.
Usage Example
const button = qs('.my-button');
addClass(button, 'active');Adds the class active to the element with the class my-button.
removeClass
The removeClass function removes a specified CSS class from an HTML element if the class is present. It ensures that the operation only proceeds when valid input is provided.
Parameters
- element (HTMLElement): The target HTML element from which the class should be removed.
- selector (string): The CSS class name to be removed from the element.
Return Value
- Returns true if the class is successfully removed.
- Returns undefined if the operation is not performed due to invalid or missing input.
Usage Example
const button = qs('.my-button');
removeClass(button, 'active');hasClass
The hasClass function checks whether a specified CSS class is present on a given HTML element. It ensures that the input parameters are valid before performing the check.
Parameters
- element (HTMLElement): The target HTML element to be checked for the specified class.
- selector (string): The CSS class name to check for.
Return Value
- Returns true if the element contains the specified class.
- Returns false if the class is not present or if the input is invalid.
Usage Example
const button = qs('.my-button');
if (hasClass(button, 'active')) {
console.log('Button is active!');
}toggleClass
The toggleClass function toggles a specified CSS class on a given HTML element. It ensures that the input parameters are valid before performing the toggle.
Parameters
- element (HTMLElement): The target HTML element to be checked for the specified class.
- selector (string): The CSS class name to check for.
Return Value
- Returns true if the class is now present,
- Returns false if removed or invalid input.
Usage Example
const button = qs('.my-button');
if (toggleClass(button, 'active')) {
console.log(hasClass(button, 'active'));
}addPrefix
The addPrefix function is a utility that applies a CSS class to the root element of a document. It is typically used to add a global modifier or theme-related class for styling purposes.
Parameters
- selector (string): The name of the CSS class to be added to the element.
Return Value
- The function does not explicitly return a value but delegates to addClass, whose behavior depends on its implementation.
Usage Example
addPrefix('dark-mode');After executing this code, the element will look like this if dark-mode is successfully applied:
<html class="dark-mode">Notes
The function directly modifies the root element (document.documentElement), affecting all styles tied to the specified class.
removePrefix
The removePrefix function removes a specified CSS class from the root element of a document. It is typically used to reset or revert global styles applied to the document.
Parameters
- selector (string): The name of the CSS class to be removed from the element.
Return Value
- The function does not explicitly return a value but delegates to removeClass, whose behavior depends on its implementation.
Usage Example
removePrefix('dark-mode');After executing this code, if the class was previously applied, the element would change as follows:
<html class="">Notes
The function directly modifies the root element (document.documentElement), affecting all styles tied to the specified class.
setClickEvent
The setClickEvent function adds a click event listener to one or more elements specified by a CSS selector or direct reference. It tracks clicks by either invoking a callback function or pushing a metric event when the element is clicked. It prevents duplicate event bindings by marking elements using a data attribute.
Parameters
- selector (string | HTMLElement): A CSS selector string or a direct reference to an HTML element to which the click event listener will be added.
- prefix (string): A unique identifier used as a data attribute (data-[prefix]) to ensure that the click listener is not added multiple times to the same element.
- callback (function | string): If a function, it is executed when the element is clicked. If a string, it is assumed to be a metric identifier passed to pushMetric() for analytics tracking.
Usage Example
setClickEvent('.btn-submit', 'trackClick', event => {
console.log('Button clicked!', event.target);
});Adds a click listener to elements with the class .btn-submit and logs a message when clicked.
setClickEvent('.btn-track', 'metricTrack', 'goal_123');Tracks a metric with ID goal_123 when any element with the class .btn-track is clicked.
Notes
- Duplicate Prevention: Ensures event listeners are not added multiple times by using the data-[prefix] attribute.
- Callback Flexibility: Supports both custom callback functions and analytics tracking.
- Dependency: Relies on the elem() utility function for element selection. Ensure elem() is available for this function to work correctly.
Observer Functions
addTask
Adds a new task to the DOUGLAS Toolkit observer.
addTask('UX1234', () => {});removeTask
Removes a task from the DOUGLAS Toolkit observer by name.
removeTask('UX1234');updateConfig
Updates the observer configuration with a new config object.
updateConfig({attributes: true});Data Functions
getState
The getState function asynchronously retrieves the application state from a global store object located in window.System. The function returns a promise that resolves to the state if it is successfully retrieved or rejects in case of an error.
Return Value
- Type: Promise
- Description: Resolves to the application state retrieved from window.System.store.getState(). If the store is not available, the promise rejects with an error.
Example Usage
getState()
.then(state => {
console.log("Application state:", state);
})
.catch(error => {
console.error("Error retrieving state:", error);
});getProdId
The getProdId function extracts and returns a product ID from the current URL. It dynamically determines whether the product ID is found in the search query string or the pathname, depending on the presence of a “variant” parameter.
Return Value
- Type: string
- Description: Returns the extracted product ID from the URL.
Example Usage
const productId = getProdId();getProduct
The getProduct function asynchronously retrieves product information by dispatching a request to the global System store using the product ID derived from the current page’s URL or from a provided ID. It returns a promise that resolves with the product data or rejects if the product is not found or if an error occurs during the data retrieval process.
Parameters
- productId (string, optional): The product ID to fetch. If omitted, the function will use
getProdId()to extract the ID from the current page URL.
Return Value
- Type: Promise
- Description: Resolves with the product data retrieved from the API. If the product is not found or an error occurs, the promise rejects.
Example Usage
getProduct()
.then(product => {
console.log("Product retrieved:", product);
})
.catch(error => {
console.error("Error retrieving product:", error.message);
});
getProduct('12345')
.then(product => {
console.log("Product retrieved by ID:", product);
});getProducts
The getProducts function retrieves product data from the store's cached search results. If the variations parameter is set to true, it will fetch detailed product information for each product in the list by calling getProduct for each product code, and return an array of detailed product objects. Otherwise, it returns the cached product list from the store.
Parameters
- variations (boolean, optional): If true, fetches detailed product data for each product in the list. Defaults to false.
Return Value
- Type: Promise<any[]>
- Description: Resolves with an array of product objects. If
variationsis true, each object is a detailed product; otherwise, each object is from the cached search result.
Example Usage
// Get cached product list from the store
getProducts()
.then(products => {
console.log("Cached products:", products);
})
.catch(error => {
console.error("Error retrieving products:", error.message);
});
// Get detailed product data for each product in the list
getProducts(true)
.then(productsWithDetails => {
console.log("Detailed products:", productsWithDetails);
});Util Functions
scrollTo
The scrollTo function smoothly scrolls the page to a specified vertical position (pixel) over a given duration (duration). It uses an easing function (easeInOutQuad) to create a smooth scrolling animation.
Parameters
- pixel (number): The target vertical scroll position (in pixels) to scroll to. This value can be any integer representing the desired scroll position from the top of the page.
- duration (number): The duration (in milliseconds) over which the scroll animation should take place. This determines how quickly the page will scroll to the specified position.
Easing Function (easeInOutQuad)
The easing function Math.easeInOutQuad provides a smooth, non-linear transition, starting slowly, accelerating in the middle, and then decelerating towards the end. This creates a more natural, visually pleasing scroll animation.
Usage Example
const scrollToPosition = 2000;
const scrollSpeed = 500;
scrollTo(scrollToPosition, scrollSpeed);Notes
- The scroll position is updated for both document.documentElement and document.body to ensure compatibility across different browsers and document structures.
- The function creates a smooth scroll effect using the easeInOutQuad easing method.
- The scroll occurs asynchronously, with a timeout of 20ms between each update to the scroll position (increment).
- To stop or interrupt the scroll, you would need to add external logic to cancel the timeouts or animations.
Potential Improvements
If you need to ensure better performance, consider using requestAnimationFrame instead of setTimeout, which can optimize the animation for smoother performance, especially on devices with lower processing power.
inViewport
Note: If you are using an SPA framework or library and your element is suddenly no longer observed, an adjustment to the function may be necessary. I have marked a TODO here, which you can activate as required.
The inViewport function is used to monitor an HTML element’s visibility in the viewport as the user scrolls. When the element enters or exits the viewport, the provided callback function is invoked. This can be useful for triggering certain actions when an element becomes visible, such as lazy loading content or triggering animations.
Parameters
- selector (string | HTMLElement):
- If a string is provided, it should be a CSS selector that will be used to find the element within the document.
- If an HTMLElement is provided, the function directly uses it to check for visibility.
- prefix (string): A unique string used as a prefix to avoid duplicate event listeners. It is also used to mark elements with a custom data attribute to track if the element has already been processed.
- callback (function): A function that will be invoked whenever the visibility status of the element changes (when it enters or exits the viewport). It is passed the current visibility status (true if in the viewport, false if not).
Return Value
The function does not return any value. Instead, it triggers the callback whenever the element enters or exits the viewport.
Usage Example
inViewport('.my-element', 'elementPrefix', status => {
if (status) {
console.log('The element is now in the viewport!');
} else {
console.log('The element is no longer in the viewport!');
}
});This will monitor the visibility of an element with the class .my-element. The callback will log a message when the element enters or exits the viewport.
const myElement = qs('.my-element');
inViewport(myElement, 'elementPrefix', (status) => {
if (status) {
console.log('The element is now in the viewport!');
} else {
console.log('The element is no longer in the viewport!');
}
});This will monitor the visibility of the myElement directly, using the provided HTMLElement.
Notes
- The function adds an event listener for the scroll event on the window, which may trigger frequently. If performance becomes an issue, consider throttling or debouncing the scroll event handler.
- This function is particularly useful in Single Page Applications (SPAs) or dynamic content sites, where elements may be loaded dynamically and visibility checks need to be performed after the element is rendered.
isElementInViewport
The isElementInViewport function checks if an HTML element is currently visible within the viewport. It determines whether the element is fully or partially visible, and also checks if the element is positioned below the top of the viewport.
Parameters
- element (HTMLElement): The target HTML element to check for visibility within the viewport.
Return Value
Returns an object with two properties:
- below (boolean):
- true if the element is positioned below the top of the viewport.
- false if the element is above the top of the viewport.
- status (boolean):
- true if the entire element is visible within the viewport (the element’s top, bottom, left, and right edges must all be within the bounds of the viewport).
- false if any part of the element is outside the viewport.
If the element’s width and height are 0, the function will return undefined since the element is not considered visible.
Usage Example
const element = qs('.my-element');
const visibility = isElementInViewport(element);
if (visibility && visibility.status) {
console.log('The element is fully visible in the viewport.');
} else {
console.log('The element is not fully visible in the viewport.');
}Checks whether an element with the class .my-element is fully visible in the viewport and logs the result.
const element = qs('.my-element');
const visibility = isElementInViewport(element);
if (visibility && visibility.below) {
console.log('The element is below the top of the viewport.');
} else {
console.log('The element is above the top of the viewport.');
}Checks if the element is below the top of the viewport.
Notes
- Zero Dimensions: If the element has 0 width and 0 height, the function returns undefined as it cannot be considered visible.
- Edge Boundaries: The status will return false if any edge of the element is outside the viewport (even if only partially).
isMobile
The isMobile function detects if the current user is accessing the website from a mobile device by examining the user agent string of the browser.
Return Value
- Boolean: true if the user agent string contains “android” or “mobile”, indicating a mobile device, false otherwise.
Usage Example
if (isMobile()) {
console.log('User is on a mobile device.');
} else {
console.log('User is on a desktop or non-mobile device.');
}Notes
- This function provides a simple check for mobile devices but may not cover all edge cases or device types.
- It may return true for some tablets or hybrid devices depending on their user agent strings.
- For more robust device detection, consider using dedicated libraries like Modernizr or Mobile Detect.
getWidth
The getWidth function calculates and returns the maximum width of the current document, accounting for different properties that reflect the document’s width under various scenarios.
Return Value
- Number: The maximum width of the document in pixels.
Usage Example
const pageWidth = getWidth();
console.log(`The current document width is ${pageWidth}px.`);Notes
- This function is useful when needing to adapt UI elements or layouts based on the total document width.
- It accounts for varying browser implementations and conditions such as scrollbars or borders that might affect width calculations.
setCookie
The setCookie function creates or updates a cookie with a specified name, value, and expiration date. It sets the cookie to be accessible across the entire website by using a path of /.
Parameters
- cookieName (string): The name of the cookie to be set.
- cookieValue (string): The value to be assigned to the cookie.
- expiryDays (number): The number of days until the cookie expires.
Usage Example
// This code creates a cookie named username with the value JohnDoe that will expire in 7 days.
setCookie("username", "JohnDoe", 7);Notes
- Cookies set by this function are accessible site-wide (path=/).
- Ensure cookie names are unique to avoid overwriting existing cookies.
getCookie
The getCookie function retrieves the value of a specified cookie from the browser’s document.
Parameters
- cookieName (string): The name of the cookie whose value you want to retrieve.
Return Value
- String: The value of the specified cookie.
- Returns an empty string ("") if the cookie does not exist.
Usage Example
document.cookie = "username=JohnDoe";
const username = getCookie("username");
if (username) {
console.log(`Welcome back, ${username}!`);
} else {
console.log("No username cookie found.");
}Notes
- The function assumes the cookie format follows the standard name=value convention.
- Special characters in cookie values are handled correctly due to decodeURIComponent().
getStore
The getStore function retrieves data from a specified storage (localStorage or sessionStorage) and optionally returns a specific property of the stored data object. The function handles JSON parsing and gracefully manages errors if the stored data is not in a valid JSON format.
Parameters
- name (string): The key name under which the data is stored.
- key (string | null) [optional]: The property to retrieve from the stored object. If omitted or null, the entire object is returned.
- storage (string) [optional]: The storage type from which to retrieve the data. Options: "localStorage" (default) or "sessionStorage".
Usage Example
const theme = getStore('userSettings', 'theme');
console.log(theme); // Outputs: 'dark'Without a second parameter as a key, you get the entire data object back
const data = getStore('myExampleObject');setStore
The setStore function saves or updates an object in client-side storage (localStorage or sessionStorage). It merges the new key-value pair with existing data stored under the specified name key, ensuring structured data persistence across user sessions.
Parameters
- name (string): The name of the storage key used to save or retrieve the data.
- key (string): The property name in the object to store or update.
- value (any): The value associated with the specified key.
- storage (string) [optional]: Specifies the storage type. Options are: "localStorage" (default) or "sessionStorage"
Usage Example
setStore('userSettings', 'theme', 'dark');This stores { theme: 'dark' } in localStorage under the key 'userSettings'.
setStore('sessionData', 'isAuthenticated', true, 'sessionStorage');This stores { isAuthenticated: true } in sessionStorage under the key 'sessionData'.
Notes
- The function relies on a properly implemented getStore() function to retrieve existing data.
- Data is stored as JSON strings and should be parsed back into objects when retrieved.
- Storage Limits: Both localStorage and sessionStorage typically have a 5MB storage limit.
- Best Practices: Avoid storing sensitive information in client-side storage for security reasons.
setMutationObserver
The setMutationObserver function sets up a MutationObserver on a DOM element matching the given selector. The observer watches for mutations (changes) to the element, and when such changes occur, it triggers the provided callback function. This function returns a promise, resolving once the observer is successfully set, or rejecting if any errors occur.
Parameters
- selector (string): The CSS selector used to find the target DOM element to observe.
- prefix (string): A unique identifier used as a data attribute (data-[prefix]) to ensure that the observer is not added multiple times to the same element.
- callback (function): The callback function to be executed when mutations are detected on the target element.
- options (object): An optional object specifying which mutations should be observed. The default value is:
- attributes: Observe changes to the element’s attributes.
- childList: Observe changes to the child nodes of the element.
- subtree: Observe changes to the entire subtree of the element.
Return Value
Returns a Promise: Resolves when the mutation observer is successfully set up. Rejects if the provided callback is not a function or if any errors occur during the process.
Usage Example
setMutationObserver('.example', 'experimentPrefix', () => {
console.log('Mutation detected on the element!');
});Notes
- Element Selection: Uses elemSync(selector) to select the element synchronously. If the element is not found, the promise will reject.
- Observer Activation: The observer is activated only once for each element, as indicated by the data-[prefix] attribute.
- Error Handling: If the callback is not a function, or if an error occurs while setting up the observer, the promise is rejected with an error message.
- Mutation Types: By default, the observer listens for changes to attributes, child nodes, and the entire subtree. These can be customized via the options parameter.
getPage
The getPage function determines the current page type based on the URL pathname. It optionally checks if the user is in the checkout process and categorizes the page accordingly. The function supports various page types, including home, product, search, brand, login, cart, and confirmation pages.
Page Type Categories
Page Type | Description | Condition |---|---|---| "home" | Homepage | Path matches regional homepage pattern "pop" | Popular or category page | Path contains "/c/" "pdp" | Product detail page (PDP) | Path contains "/p/" "brand" | Brand-specific page | Path contains "/b/" "search" | Search results page | Path contains "/search" "login" | Login page | Path contains "/login" "cart" | Cart page | Path contains "/cart" "checkout" | Checkout process page (if inCheckout is true) | Path contains "/checkout/" "confirm" | Post-checkout confirmation page | Path contains "/checkout/thankyou" "no-checkout"| Non-checkout page when in checkout mode | Path doesn’t contain "/checkout/"
Usage Example
Determine Page Type
const pageType = getPage();
console.log("Current Page:", pageType); // e.g., "home" or "cart"Check if in Checkout
const pageType = getPage(true);
console.log("Checkout Page Type:", pageType); // e.g., "checkout" or "no-checkout"pageChange
The pageChange function monitors changes in the browser’s URL without requiring a full page reload. It listens for changes triggered by pushState, replaceState, and popstate events, ensuring that a callback function is executed whenever the URL changes. This is particularly useful in Single Page Applications (SPAs) where navigation happens dynamically.
Usage Example
pageChange('experimentPrefix', () => {
console.log('URL changed:', window.location.href);
});// Example of changing the URL
history.pushState({}, '', '/test'); // Logs: "URL changed: http://www.douglas.de/de/test"goTo
The goTo function is a utility designed to navigate to a specified URL using the System.history.history.push method, if available. It ensures that navigation attempts do not result in errors if System or its nested properties are undefined.
Usage Example
// Navigating to a new page
const newPage = "/dashboard";
goTo(newPage);loadLibrary
The loadLibrary function dynamically loads an external JavaScript library from a given URL and ensures it is only loaded once.
If the script is already present in the document, it resolves immediately with the existing script element.
Parameters
src(string): The URL of the CDN-hosted library to load.prefix(string): A unique attribute name to prevent multiple initializations of the same script.async(boolean, optional): Whether to load the script asynchronously. Defaults totrue.
Returns
Promise<HTMLScriptElement>: Resolves with the script element once loaded, or rejects if the loading fails.
Usage Example
// Load Lodash from CDN
loadLibrary('https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js', 'experimentPrefix')
.then(() => {
// Now you can use _
console.log('Lodash loaded:', typeof _ !== 'undefined');
})
.catch(err => {
console.error('Failed to load library:', err);
});addStyleToBody
The addStyleToBody function injects a CSS string into the document head, using a unique prefix as a data attribute to prevent duplicate style insertions.
If a style element with the given prefix already exists, it does nothing. Otherwise, it creates and appends a new style element.
This function is especially useful as a CSS "trick" for A/B testing platforms like Kameleoon, where injected CSS may be removed when the experiment is deactivated, but JavaScript is still executed on the page. By injecting styles dynamically via JavaScript, you can ensure your experiment's styles persist as long as your script runs.
Parameters
css(string): The CSS string to be injected.prefix(string): The unique prefix used as a data attribute to identify the style element.
Usage Example
// Inject custom minified styles for an experiment
const css = '.custom-selector{display: none !important;}';
addStyleToBody(css, 'experimentPrefix');Hotjar
The hotjar function triggers a Hotjar event for tracking user interactions by sending a unique event key to the Hotjar API. The function ensures that each event key is only triggered once per page load by maintaining a list of already transmitted keys.
Parameters
- key (string): Description: A unique identifier for the Hotjar event to be tracked.
Usage Example
hotjar('your-event-key');License
Copyright (c) 2025 PARFÜMERIE Douglas GmbH & CO. KG.
Licensed under The MIT License (MIT).
