{"version":3,"file":"gtm_measurements.js","mappings":"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","sources":["webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/buildCallback.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/defaultConfig.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/sendPageViewEvent.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/normalization.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/index.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/extractLinkAttributes.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/standardisedClickTracking.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/util.js","webpack://market-storefront/./node_modules/@envato/gtm-analytics/src/sendAnalyticsEvent.js","webpack://market-storefront/webpack/bootstrap","webpack://market-storefront/./app/javascript/packs/gtm_measurements.js"],"sourcesContent":["/**\n * Wraps a provided dataLayer callback function in some additional checks. Ensures that the\n * callback is only run in response to the dataLayer message being processed by a Google\n * Analytics container, and not other containers. Also sets a 500ms timeout after which the\n * callback will be run if it has not yet been run by GTM.\n * @param {?Function} originalCallback\n * @returns {?Function}\n */\nconst buildCallback = (originalCallback) => {\n  if (!originalCallback) return null\n\n  // GTM will not be running at all if it's blocked by Cookiebot, an ad blocker, or a browser with strong privacy settings.\n  // So we register a callback that is fired after 500ms in case GTM never gets to process the event.\n  const eventCallbackFallback = setTimeout(originalCallback, 500)\n\n  return (containerId) => {\n    // This callback is fired for every \"tag\" that is registered in Google Tag Manager.\n    // e.g. once for Google Analytics, and once for Google Ads.\n    // We have to check the container ID starts with \"G-\" to know it's a Google Analytics callback.\n    if (containerId?.startsWith(\"G-\")) {\n      // This fires when the GA event has successfully been recorded.\n      // We remove our fallback timer and call the callback function.\n      clearTimeout(eventCallbackFallback)\n      originalCallback()\n    }\n  }\n}\n\nmodule.exports = buildCallback\n","/**\n * @typedef Config\n * @property {string} [elementsDomain]\n * @property {string[]} [marketDomains]\n * @property {string} [tutsplusDomain]\n * @property {string[]} [skipNormalizationForAttributes]\n */\n\n/**\n * Default configuration for the library.\n * @type {Config}\n */\nconst defaultConfig = {\n  elementsDomain: \"elements.envato.com\",\n  marketDomains: [\n    \"themeforest.net\",\n    \"codecanyon.net\",\n    \"audiojungle.net\",\n    \"videohive.net\",\n    \"graphicriver.net\",\n    \"photodune.net\",\n    \"3docean.net\",\n    \"marketplace.envato.com\",\n    \"market.envato.com\",\n    \"envatomarketplaces.com\",\n  ],\n  tutsplusDomain: \"tutsplus.com\",\n  skipNormalizationForAttributes: [\"elements_item_id\"], // Deprecated: 'elements_item_id' will be removed from this list in the next major release.\n};\n\nmodule.exports = defaultConfig;\n","const { deepNormalizeAttributes } = require('./normalization')\nconst { isNonEmptyObject } = require('./util')\nconst buildCallback = require('./buildCallback')\n\n/**\n * Pushes the provided `eventData` object to the `window.dataLayer` array.\n * `window.dataLayer` will be created as an empty array if it does not yet exist.\n * @param {Object} [eventData]\n */\nconst pushToDataLayer = (eventData) => {\n  window.dataLayer = window.dataLayer || []\n\n  window.dataLayer.push(eventData)\n}\n\n/**\n * @typedef sendPageViewEventOptions\n * @property {Object} pageAttributes\n * @property {?Object} [userAttributes]\n * @property {?Function} [callback]\n * @property {?(import('./defaultConfig').Config)} [customConfig]\n */\n\n/**\n * Sets new page attributes by pushing them to the dataLayer, and then triggers a page view\n * event by pushing an 'analytics_ready' message to the dataLayer afterwards.\n * @param {sendPageViewEventOptions} options\n * @returns {void}\n */\nconst sendPageViewEvent = ({\n  pageAttributes,\n  userAttributes = null,\n  callback = null,\n  customConfig = {},\n}) => {\n  const pageAttributesPayload = {\n    ...deepNormalizeAttributes(pageAttributes, { stringifyArrays: true, customConfig }),\n    event_attributes: null, // Clear any previous event attributes data from the dataLayer\n  }\n\n  // We only want to include `user_attributes` in the payload if we have new user attributes to set.\n  if (isNonEmptyObject(userAttributes)) {\n    pageAttributesPayload.user_attributes = deepNormalizeAttributes(userAttributes, { stringifyArrays: true, customConfig })\n  }\n\n  pushToDataLayer(pageAttributesPayload)\n\n  pushToDataLayer({\n    event: 'analytics_ready',\n    eventCallback: buildCallback(callback),\n    event_attributes: {\n      event_type: 'user',\n      custom_timestamp: Date.now(),\n    }\n  })\n}\n\nmodule.exports = sendPageViewEvent\n","const defaultConfig = require('./defaultConfig')\nconst { isObject } = require('./util')\n\n// Normalize event data following the specs in our implementation guide:\n// https://www.notion.so/GA4-Event-implementation-guide-3f309f96f44740c1b2f6e0fe4484310c#1bfb3e7ee4664f9da20b070df2be2fb8\n// Keys are snake_cased and values are lowercased.\n// Pass `stringifyArrays: true` to flatten arrays and convert them to comma-separated strings.\nconst deepNormalizeAttributes = (theObject, { stringifyArrays = false, customConfig = {} } = {}) => {\n  const config = { ...defaultConfig, ...customConfig }\n\n  if (Array.isArray(theObject)) {\n    if (stringifyArrays) return normalizeAttributeValue(theObject)\n\n    return theObject.map((value) => deepNormalizeAttributes(value, { stringifyArrays, customConfig }))\n  }\n\n  if (isObject(theObject)) {\n    const normalizedObject = {}\n\n    Object.entries(theObject).forEach(([key, value]) => {\n      const normalizedKey = normalizeAttributeKey(key)\n\n      if (config.skipNormalizationForAttributes.includes(key) || config.skipNormalizationForAttributes.includes(normalizedKey)) {\n        normalizedObject[normalizedKey] = value || undefined\n        return\n      }\n\n      normalizedObject[normalizedKey] = deepNormalizeAttributes(value, { stringifyArrays, customConfig })\n    })\n\n    return normalizedObject\n  }\n\n  return normalizeAttributeValue(theObject)\n}\n\nconst normalizeAttributeKey = (key) => {\n  return key\n    .replace(/\\W+|\\B(?=[A-Z])/g, '_')\n    .toLowerCase()\n    .replace(/[\\s_]+/g, '_')\n    .replace(/^_+|_+$/g, '')\n}\n\n// This `normalizeAttributeValue` function is duplicated in some other repositories, for reasons:\n// - https://github.com/envato/mixkit/blob/e2fe5c5/app/components/components/google_tag_manager_body.html.erb\n// - https://github.com/envato/tutsplus/blob/0325d08/hub/app/components/google_tag_manager_body_component/google_tag_manager_body_component.html.erb\n// - https://github.com/envato/market-storefront/blob/771cbed/app/components/shared/html_body/google_tag_manager_page_attributes_component.html.erb\n// - https://github.com/envato/marketplace/blob/0269e47/app/views/common/_set_page_attributes.html.erb\n// If it's updated here, please mention that in the changelog and let the owners of the above repos know that they should update their copy to match.\nconst normalizeAttributeValue = (value) => {\n  if (value === undefined || value === null) return undefined\n\n  let normalizedValue\n\n  if (Array.isArray(value)) {\n    normalizedValue = normalizedValue || value\n      .map(normalizeAttributeValue)\n      .filter(Boolean)\n      .join(', ')\n  }\n\n  normalizedValue = normalizedValue || value\n    .toString()\n    .toLowerCase()\n    .trim()\n    .replace(/&amp;/g, '&')\n    .replace(/&#39;/g, \"'\")\n    .replace(/\\s+/g, ' ')\n\n  if (normalizedValue === '') return undefined\n  return normalizedValue\n}\n\nmodule.exports = {\n  deepNormalizeAttributes,\n  normalizeAttributeKey,\n  normalizeAttributeValue\n}\n","const {\n  deepNormalizeAttributes,\n  normalizeAttributeKey,\n  normalizeAttributeValue,\n} = require(\"./normalization\");\nconst sendAnalyticsEvent = require(\"./sendAnalyticsEvent\");\nconst sendPageViewEvent = require(\"./sendPageViewEvent\");\nconst standardisedClickTracking = require(\"./standardisedClickTracking\");\nconst extractLinkAttributes = require(\"./extractLinkAttributes\");\n\nmodule.exports = {\n  deepNormalizeAttributes,\n  normalizeAttributeKey,\n  normalizeAttributeValue,\n  sendAnalyticsEvent,\n  sendPageViewEvent,\n  standardisedClickTracking,\n  extractLinkAttributes,\n};\n","const defaultConfig = require(\"./defaultConfig\");\n\nconst isMarketHost = (host, domains) => {\n  return domains.some((domain) => host.endsWith(domain));\n};\n\nconst extractEventName = (\n  targetUrl,\n  { elementsDomain, marketDomains, tutsplusDomain }\n) => {\n  const currentUrl = window.location.host;\n  // eventName will be 'internal_click' by default, but we can override it here if the URL is pointing to another site\n  if (targetUrl.host === currentUrl) return \"internal_click\";\n  if (targetUrl.host.endsWith(elementsDomain)) {\n    if (currentUrl.endsWith(elementsDomain)) {\n      return \"internal_click\";\n    } else {\n      return \"elements_click\";\n    }\n  }\n  if (isMarketHost(targetUrl.host, marketDomains)) {\n    if (isMarketHost(currentUrl, marketDomains)) {\n      return \"internal_click\";\n    } else {\n      return \"market_click\";\n    }\n  }\n  if (targetUrl.host === \"placeit.net\") return \"placeit_click\";\n  if (\n    targetUrl.host.endsWith(tutsplusDomain) &&\n    currentUrl.endsWith(tutsplusDomain)\n  )\n    return \"internal_click\";\n\n  return \"external_click\";\n};\n\n/**\n * @typedef LinkAttributes\n * @property {?string} [linkUrl]\n * @property {?string} [linkDomain]\n * @property {?string} [linkQuery]\n * @property {?string} [linkAnchor]\n * @property {?string} [eventName]\n */\n\n/**\n * Extracts link attributes from an HTML element.\n * @param {(HTMLElement|HTMLAnchorElement)} element\n * @param {?(import('./defaultConfig').Config)} [customConfig]\n * @returns {LinkAttributes}\n */\nconst extractLinkAttributes = (element, customConfig = {}) => {\n  const config = { ...defaultConfig, ...customConfig };\n  const linkAttributes = {};\n\n  // If this element isn't a link, it won't have any link attributes for us to extract.\n  if (!element || !element.href) return linkAttributes;\n\n  // If the `href` is just a path without a host/origin, we need to provide a base URL for it.\n  // `HTMLAnchorElement.href` is a stringifier so it _should_ always have a host:\n  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/href\n  // but we provide the URL of the current page as the optional `base` argument to cover any unexpected edge cases.\n  const targetUrl = new URL(element.href, window.location.href);\n\n  // If this is something other than a regular web link (e.g. a mailto: link), treat it as an external link\n  // and don't try to extract any web-specific attributes from it. Just set the whole thing as the linkUrl.\n  if (![\"https:\", \"http:\"].includes(targetUrl.protocol)) {\n    linkAttributes.eventName = \"external_click\";\n    linkAttributes.linkUrl = targetUrl.toString();\n    return linkAttributes;\n  }\n\n  const queryParams = targetUrl.searchParams;\n  queryParams.delete(\"_ga\"); // Remove _ga autolinker query param, it'll just create noise in GA\n\n  linkAttributes.linkUrl = targetUrl.origin + targetUrl.pathname;\n  linkAttributes.linkDomain = targetUrl.host;\n  linkAttributes.linkQuery = queryParams.toString();\n  linkAttributes.linkAnchor = targetUrl.hash;\n\n  linkAttributes.eventName = extractEventName(targetUrl, config);\n\n  return linkAttributes;\n};\n\nmodule.exports = extractLinkAttributes;\n","const sendAnalyticsEvent = require('./sendAnalyticsEvent')\nconst defaultConfig = require('./defaultConfig')\nconst extractLinkAttributes = require('./extractLinkAttributes')\n\nconst standardisedClickTracking = (event, customConfig = {}) => {\n  const config = {...defaultConfig, ...customConfig}\n  // Find out if this click event has an element we want to track.\n  // Try the clicked element first, then look for any parent elements that might be trackable.\n  const element = [event.target, event.target.closest('a, [data-analytics-click-label]')].find(isElementTrackable)\n\n  // If the element that was clicked is not something we want to track, return early.\n  if (!element) return\n\n  const linkAttributes = extractLinkAttributes(element, config)\n\n  // See the GA4 Event Attributes Catalogue for a description of these attributes:\n  // https://www.notion.so/853a20e4ed93407481bd68dc0ba27741?v=dfcbd9e925d24db5bb1e14172b9dbbba\n  const attributes = {\n    eventName: 'internal_click', // This may be overridden by linkAttributes below depending on the link URL.\n    context: element.closest('[data-analytics-context]')?.dataset.analyticsContext,\n    contextDetail: element.closest('[data-analytics-context-detail]')?.dataset.analyticsContextDetail,\n    elementId: element.closest('[data-analytics-element-id]')?.dataset.analyticsElementId,\n    textContent: element.closest('[data-analytics-text-content]')?.dataset.analyticsTextContent,\n    clickLabel: extractClickLabel(element),\n    clickType: element.tagName,\n    ...linkAttributes,\n    customConfig,\n  }\n\n  sendAnalyticsEvent(attributes)\n}\n\nconst extractClickLabel = (element) => (\n  [\n    element.dataset.analyticsClickLabel,\n    element.textContent?.trim(),\n    element.attributes.title?.value.trim(),\n    element.attributes['aria-label']?.value.trim(),\n    element.attributes.alt?.value.trim()\n  ].find(Boolean)\n)\n\nconst isElementTrackable = (element) => {\n  // Handle undefined/null\n  if (!element) return false\n\n  // Make it possible for elements with their own custom tracking code to opt-out of these standardised events\n  // by setting a `data-analytics-has-custom-tracking=\"true\"` attribute on either the element or a parent element\n  if (element.closest('[data-analytics-has-custom-tracking=\"true\"]')) return false\n\n  // All links should be trackable\n  if (element.tagName === 'A') {\n    const elementHref = element.attributes.href?.value.trim()\n\n    if (!elementHref) return false // unless their href is missing or empty\n\n    if (isBlockedHref(elementHref)) return false\n\n    return true\n  }\n\n  // Any element with a data-analytics-click-label attribute is trackable\n  if (element.dataset.analyticsClickLabel !== undefined) return true\n\n  // Otherwise this is some other element we don't care about tracking.\n  return false\n}\n\nconst matchHrefToString = str => { return (href) => href === str }\nconst matchHrefToRegexp = re => { return (href) => re.test(href) }\n\nconst hrefBlockList = [\n  matchHrefToString('#'),\n  matchHrefToRegexp(/^javascript:/)\n]\n\nconst isBlockedHref = href => hrefBlockList.some(checkFunction => checkFunction(href))\n\nmodule.exports = standardisedClickTracking\n","const isObject = (possiblyObject) => (\n  typeof possiblyObject === 'object' &&\n  Object.prototype.toString.call(possiblyObject) === '[object Object]'\n)\n\nconst isNonEmptyObject = (possiblyObject) => (\n  isObject(possiblyObject) && Object.keys(possiblyObject).length > 0\n)\n\nmodule.exports = {\n  isObject,\n  isNonEmptyObject\n}\n","const { deepNormalizeAttributes } = require('./normalization')\nconst { isNonEmptyObject } = require('./util')\nconst buildCallback = require('./buildCallback')\n\nconst pushToDataLayer = (eventData) => {\n  window.dataLayer = window.dataLayer || []\n\n  window.dataLayer.push(eventData)\n}\n\n/**\n * @typedef SendAnalyticsEventOptions\n * @property {?string} [eventName]\n * @property {?string} [eventType]\n * @property {?Function} [callback]\n * @property {?Object} [ecommerce]\n * @property {?Object} [userAttributes]\n * @property {?(import('./defaultConfig').Config)} [customConfig]\n * @property {...Object} [eventAttributes]\n */\n\n/**\n * Send an analytics event by pushing it to the dataLayer.\n * @param {SendAnalyticsEventOptions} options\n * @returns {void}\n */\nconst sendAnalyticsEvent = ({\n  eventName,\n  eventType = 'user',\n  callback = null,\n  ecommerce = null,\n  userAttributes = null,\n  customConfig = {},\n  ...eventAttributes\n}) => {\n  const eventData = {\n    event: 'track_event', // This may be overridden to 'e-commerce' below if this event contains ecommerce data.\n    event_name: eventName,\n    event_attributes: {\n      event_type: eventType,\n      custom_timestamp: Date.now(),\n      ...deepNormalizeAttributes(eventAttributes, { stringifyArrays: true, customConfig })\n    },\n    eventCallback: buildCallback(callback)\n  }\n\n  // Clear any previous event attributes data from the dataLayer\n  const preEventPayload = { event_attributes: null }\n\n  if (isNonEmptyObject(userAttributes)) eventData.user_attributes = deepNormalizeAttributes(userAttributes, { stringifyArrays: true, customConfig })\n\n  if (isNonEmptyObject(ecommerce)) {\n    eventData.event = 'e-commerce'\n    eventData.ecommerce = deepNormalizeAttributes(ecommerce, { customConfig })\n\n    // Clear any previous ecommerce data from the dataLayer\n    preEventPayload.ecommerce = null\n  }\n\n  pushToDataLayer(preEventPayload)\n\n  // Push the event into Google Tag Manager:\n  pushToDataLayer(eventData)\n}\n\nmodule.exports = sendAnalyticsEvent\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","import GtmAnalytics from '@envato/gtm-analytics'\n\nconst safeJsonParse = (unknownBlob) => {\n  if (!unknownBlob) return undefined\n\n  try {\n    return JSON.parse(unknownBlob)\n  } catch (error) {\n    if (document.body.dataset.railsEnv) {\n      const errorTracker = window.Rollbar || console\n      errorTracker.error('MarketClickTracking error', error)\n    }\n    return undefined\n  }\n}\n\n/**\n * Send payload to GA4 via gtm-analytics library per user click. If the click navigates to\n * another page, e.g. click target ancestor is `a[href^=http]`, then the payload is ensured\n * to be sent before navigating to another page.\n *\n * The above behavior can be amended, by having certain HTML attribute on the target or one\n * of its ancestors, as follow:\n *\n * | HTML attribute                           | Amended behavior                                        |\n * |------------------------------------------|---------------------------------------------------------|\n * | `data-analytics-has-custom-click=\"true\"` | aborts and cedes control to custom behavior             |\n * | `data-analytics-click-payload=\"...\"`     | payload consumed by gtm-analytics lib, abort if invalid |\n * | `data-analytics-context=\"...\"`           | override context of payload if absent from payload      |\n * | `data-analytics-context-detail=\"...\"`    | override context detail of payload if absent            |\n *\n * The gtm-analytics library is at https://github.com/envato/gtm-analytics/.\n */\nconst marketClickTracking = (event) => {\n  const hasCustomClick = event.target.closest('[data-analytics-has-custom-click=\"true\"]')\n  if (hasCustomClick) return\n\n  const payloadElement = event.target.closest('[data-analytics-click-payload]')\n  if (payloadElement) {\n    const payload = safeJsonParse(payloadElement.dataset?.analyticsClickPayload)\n    if (!payload) return\n\n    payload.context ??= event.target.closest('[data-analytics-context]')?.dataset?.analyticsContext\n    payload.contextDetail ??= event.target.closest('[data-analytics-context-detail]')?.dataset?.analyticsContextDetail\n\n    const anchor = event.target.closest('a')\n    const turboDisabled = event.target.closest('[data-turbo]')?.dataset?.turbo === 'false'\n    const usingTurbo = !turboDisabled && event.target.closest('[data-turbo-frame]')\n    const delayNavigation = anchor?.href?.startsWith('http') && !usingTurbo\n    if (delayNavigation) {\n      event.preventDefault()\n      payload.callback ??= () => window.open(anchor.href, anchor.target || '_self')\n    }\n\n    GtmAnalytics.sendAnalyticsEvent(payload)\n  } else {\n    GtmAnalytics.standardisedClickTracking(event)\n  }\n}\n\nconst addMarketClickTrackingOnce = () => {\n  const marketClickTrackingSymbol = Symbol.for('marketClickTracking')\n  if (window[marketClickTrackingSymbol]) return\n  window[marketClickTrackingSymbol] = marketClickTracking\n\n  document.addEventListener('click', window[marketClickTrackingSymbol])\n}\n\naddMarketClickTrackingOnce()\n\nwindow.GtmMeasurements = GtmAnalytics\n"],"names":["module","exports","originalCallback","eventCallbackFallback","setTimeout","containerId","startsWith","clearTimeout","elementsDomain","marketDomains","tutsplusDomain","skipNormalizationForAttributes","deepNormalizeAttributes","isNonEmptyObject","buildCallback","pushToDataLayer","eventData","window","dataLayer","push","pageAttributes","userAttributes","callback","customConfig","pageAttributesPayload","stringifyArrays","event_attributes","user_attributes","event","eventCallback","event_type","custom_timestamp","Date","now","defaultConfig","isObject","theObject","config","Array","isArray","normalizeAttributeValue","map","value","normalizedObject","Object","entries","forEach","key","normalizedKey","normalizeAttributeKey","includes","undefined","replace","toLowerCase","normalizedValue","filter","Boolean","join","toString","trim","sendAnalyticsEvent","sendPageViewEvent","standardisedClickTracking","extractLinkAttributes","isMarketHost","host","domains","some","domain","endsWith","element","linkAttributes","href","targetUrl","URL","location","protocol","eventName","linkUrl","queryParams","searchParams","delete","origin","pathname","linkDomain","linkQuery","linkAnchor","hash","currentUrl","extractEventName","extractClickLabel","dataset","analyticsClickLabel","textContent","attributes","title","alt","find","isElementTrackable","closest","tagName","elementHref","isBlockedHref","hrefBlockList","str","re","test","checkFunction","target","context","analyticsContext","contextDetail","analyticsContextDetail","elementId","analyticsElementId","analyticsTextContent","clickLabel","clickType","possiblyObject","prototype","call","keys","length","eventType","ecommerce","eventAttributes","event_name","preEventPayload","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","marketClickTracking","payloadElement","payload","unknownBlob","JSON","parse","error","document","body","railsEnv","Rollbar","console","safeJsonParse","analyticsClickPayload","anchor","usingTurbo","turbo","preventDefault","open","GtmAnalytics","addMarketClickTrackingOnce","marketClickTrackingSymbol","Symbol","for","addEventListener","GtmMeasurements"],"ignoreList":[],"sourceRoot":""}