npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@douglas.onsite.experimentation/douglas-ab-testing-toolkit

v3.0.4

Published

DOUGLAS A/B Testing Toolkit

Readme

DOUGLAS A/B Testing Toolkit

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

Install with npm:

npm install douglas-toolkit

Install with yarn:

yarn add douglas-toolkit

Usage Example

import { elem } from 'douglas-toolkit';

elem('#example', (example) => {
    // do something...
});

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

  1. If selector is a string, it is converted into a function that queries elements using qsa(selector).
  2. The function iteratively checks for the presence of elements or evaluates the condition every 33 milliseconds.
  3. If elements are found or the condition returns a truthy value, the callback is invoked with the result.
  4. 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

The code comment about resolving with false after 10 seconds appears to be misleading since the function does not implement such logic. If this behavior is required, it needs to be explicitly added.

share

If you want to share JavaScript code between multiple files, you can use the share function.

The share function adds a new method (func) to the global AB_TESTING_TOOLKIT object under the specified name (name). This function is typically used for A/B testing scenarios to dynamically extend the toolkit with custom functions. After adding the function, it logs a message to the console and executes an optional exec function, if defined.

Parameters

  • name (string): The name of the method being added to the AB_TESTING_TOOLKIT object. This name will be used as a key under which the func will be stored.
  • func (function): The function that will be associated with the specified name and added to the AB_TESTING_TOOLKIT object. This function can be any custom logic you wish to add to the toolkit.

Usage Example

share("myCustomFunction", () => {
    console.log("This is my custom function for A/B testing!");
});

The share function returns window.AB_TESTING_TOOLKIT, if you want to use it directly.

// Calling the added function
window.AB_TESTING_TOOLKIT.myCustomFunction();

Notes

  • The function is useful in scenarios like A/B testing frameworks where new functionalities or methods need to be dynamically added to a global toolkit.
  • The exec function, if defined, will be invoked after the function is added. This is useful for triggering additional actions after extending the toolkit.
  • The AB_TESTING_TOOLKIT object is intended to store shared functionality that can be accessed globally throughout the application.

exec

The exec function manages and executes functions stored in the AB_TESTING_TOOLKIT global object. It can immediately execute a specified function if it exists or queue the function for execution later. The function also provides a mechanism to execute all queued functions in the toolkit.

Parameters

  • name (string): The name of the function in AB_TESTING_TOOLKIT to be executed. If name is omitted, all queued functions are executed instead.
  • params (any): Parameters to pass to the function when it is executed. This can be any type of data supported by JavaScript, including objects, strings, numbers, or arrays.

Usage Example

// Immediately execute an existing function
exec("sampleFunction", { test: true });

// Execute all queued functions
exec();

Notes

  • The exec function allows delayed execution for functions that may not yet be defined when the call is made.
  • It uses a queue system (AB_TESTING_TOOLKIT.exec) to manage functions and parameters, ensuring they are called when available.

logError

The logError function logs detailed information about an error to the console.
It includes the error message, stack trace, a prefix to identify the source, and optional context for additional debugging.

Parameters

  • error (Error): The error object to log.
  • prefix (string, optional): A string used to identify the origin of the error (e.g., experiment ID or module).

Usage Example

try {
    // some code that may throw
} catch (err) {
    logError(err, 'myExperiment');
}

asyncSave

The asyncSave function wraps an asynchronous function in a try-catch block and automatically logs any errors using the logError utility.
It helps prevent unhandled promise rejections and ensures consistent error reporting across async operations.

Parameters

  • fn (Function): The asynchronous function to be executed safely.
  • prefix (string, optional): A label to identify the source of the function for error logging.

Returns

  • A new async function that wraps the original and handles errors internally.

Usage Example

const safeAsyncFn = asyncSave(async () => {
    // your async code here
}, 'myExperiment');
await safeAsyncFn();

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 goal_456.

Notes

  • Error Handling: Catches and logs any errors during the process, ensuring robust behavior.
  • Global State: Uses window.OE_METRICS to maintain state, which persists across function calls.

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

onst 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 variations is 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

JavaScript Cookies

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 to true.

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');

Classes

DateUtil

The DateUtil class provides a comprehensive set of utilities for date manipulation, formatting, and delivery range calculations. It supports locale-aware formatting, business day calculations, skipping weekends, custom delivery templates, and robust error handling.

Usage Examples

import DateUtil from './dateUtil.js';

// Basic Usage with Default Options
const defaultDateUtil = new DateUtil();
console.log('Default date:', defaultDateUtil.formatDate(defaultDateUtil.date));

// Custom Options
const customDateUtil = new DateUtil(null, {
    locale: 'de-DE',
    skipSundays: true,
    skipSaturdays: false,
    businessDaysOnly: false,
    cutoffHour: 22,
    cutoffMinute: 0,
    deliveryDaysMax: 2
});
console.log('Custom date:', customDateUtil.formatDate(customDateUtil.date));

// Date Formatting with Different Locales
const locales = ['de-DE', 'nl-NL', 'fr-FR', 'it-IT'];
const date = new Date('2025-05-19');
locales.forEach(locale => {
    const dateUtil = new DateUtil(date, { locale });
    console.log(`${locale} date:`, dateUtil.formatDate(date));
    console.log(`${locale} with weekday:`, dateUtil.formatWithWeekday());
});

// Delivery Range Calculations
const dateUtil = new DateUtil(new Date('2025-05-23'));
console.log('Default delivery range:', dateUtil.getDeliveryRange());
console.log('Custom delivery range:', dateUtil.getDeliveryRange({
    startDays: 2,
    endDays: 4,
    template: 'Custom delivery: {startDate} to {endDate}'
}));

// Adding Days with Different Options
const baseDate = new Date('2025-05-19');
const basicDateUtil = new DateUtil(baseDate);
console.log('Date after 5 days:', basicDateUtil.addDays(5).formatDate(basicDateUtil.date));
const businessDateUtil = new DateUtil(baseDate);
console.log('Date after 5 business days:', businessDateUtil.addDays(5, { businessDaysOnly: true }).formatDate(businessDateUtil.date));
const weekendDateUtil = new DateUtil(baseDate);
console.log('Date after 5 days (skip weekends):', weekendDateUtil.addDays(5, { skipSundays: true, skipSaturdays: true }).formatDate(weekendDateUtil.date));

// Error Handling Examples
const invalidDateUtil = new DateUtil('invalid-date');
console.log('Invalid date handled gracefully:', invalidDateUtil.formatDate(invalidDateUtil.date));
const invalidOptionsUtil = new DateUtil(null, { cutoffHour: 25 });
console.log('Invalid options handled gracefully:', invalidOptionsUtil.formatDate(invalidOptionsUtil.date));
const dateUtil3 = new DateUtil();
dateUtil3.addDays(-1);
console.log('Invalid days handled gracefully:', dateUtil3.formatDate(dateUtil3.date));

// Method Chaining
const dateUtil4 = new DateUtil(new Date('2025-05-19'));
const result = dateUtil4
    .addDays(5)
    .addDays(3, { businessDaysOnly: true })
    .formatDate(dateUtil4.date);
console.log('Chained operations result:', result);

// Different Date Formats
const dateUtil5 = new DateUtil();
console.log('From Date object:', dateUtil5.formatDate(new Date()));
console.log('From string (DD.MM.YYYY):', dateUtil5.formatDate(new DateUtil('01.01.2024').date));
console.log('From ISO string:', dateUtil5.formatDate(new DateUtil('2024-01-01').date));

// Delivery Templates for Different Locales
const deliveryTemplates = {
    'de-DE': 'Lieferzeitraum: {startDate} bis {endDate}',
    'nl-NL': 'Levertijd: {startDate} tot {endDate}',
    'fr-FR': 'Délai de livraison: du {startDate} au {endDate}',
    'it-IT': 'Tempi di consegna: dal {startDate} al {endDate}'
};
Object.entries(deliveryTemplates).forEach(([locale, template]) => {
    const dateUtil6 = new DateUtil(new Date('2025-05-19'), { locale });
    console.log(`${locale} delivery range:`, dateUtil6.getDeliveryRange({ template }));
});

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('viewed*UX-1234*variant');

License

Copyright (c) 2025 PARFÜMERIE Douglas GmbH & CO. KG.

Licensed under The MIT License (MIT).

PARFÜMERIE Douglas GmbH & CO. KG