{"version":3,"file":"frizz-hair-quiz-section.min.js","mappings":"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","sources":["webpack://lange/../node_modules/uuid/dist/rng.js","webpack://lange/../node_modules/uuid/dist/stringify.js","webpack://lange/../node_modules/uuid/dist/v4.js","webpack://lange/./sections/frizz-hair-quiz/index.ts"],"sourcesContent":["const rnds8 = new Uint8Array(16);\nexport default function rng() {\n    return crypto.getRandomValues(rnds8);\n}\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n    byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n    return (byteToHex[arr[offset + 0]] +\n        byteToHex[arr[offset + 1]] +\n        byteToHex[arr[offset + 2]] +\n        byteToHex[arr[offset + 3]] +\n        '-' +\n        byteToHex[arr[offset + 4]] +\n        byteToHex[arr[offset + 5]] +\n        '-' +\n        byteToHex[arr[offset + 6]] +\n        byteToHex[arr[offset + 7]] +\n        '-' +\n        byteToHex[arr[offset + 8]] +\n        byteToHex[arr[offset + 9]] +\n        '-' +\n        byteToHex[arr[offset + 10]] +\n        byteToHex[arr[offset + 11]] +\n        byteToHex[arr[offset + 12]] +\n        byteToHex[arr[offset + 13]] +\n        byteToHex[arr[offset + 14]] +\n        byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n    const uuid = unsafeStringify(arr, offset);\n    if (!validate(uuid)) {\n        throw TypeError('Stringified UUID is invalid');\n    }\n    return uuid;\n}\nexport default stringify;\n","import rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction v4(options, buf, offset) {\n    if (!buf && !options && crypto.randomUUID) {\n        return crypto.randomUUID();\n    }\n    return _v4(options, buf, offset);\n}\nfunction _v4(options, buf, offset) {\n    options = options || {};\n    const rnds = options.random ?? options.rng?.() ?? rng();\n    if (rnds.length < 16) {\n        throw new Error('Random bytes length must be >= 16');\n    }\n    rnds[6] = (rnds[6] & 0x0f) | 0x40;\n    rnds[8] = (rnds[8] & 0x3f) | 0x80;\n    if (buf) {\n        offset = offset || 0;\n        if (offset < 0 || offset + 16 > buf.length) {\n            throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n        }\n        for (let i = 0; i < 16; ++i) {\n            buf[offset + i] = rnds[i];\n        }\n        return buf;\n    }\n    return unsafeStringify(rnds);\n}\nexport default v4;\n","import { v4 as uuidv4 } from 'uuid';\n\n/**\n * Track the last viewed slide ID so we can associate user responses with the correct question when\n * they click an option. The quiz_progress event updates this before the user clicks.\n */\nlet lastSlideId = '';\n\n/**\n * Alphanumeric value of the email question slide ID. This is used to determine if the user has\n * submitted their email address and to emit the identity-captured event.\n */\nlet activeQuizEmailQuestionId: string;\n\n/**\n * Handles click events throughout the quiz interface. Dispatches a custom email-collected event\n * when the user submits the email form (for marketing automation integration) and tracks quiz\n * question responses for analytics when the user selects an answer option.\n */\nfunction onClick(event: MouseEvent) {\n  if (!(event.target instanceof HTMLElement)) {\n    return;\n  }\n\n  const selector = `.tangent_${activeQuizEmailQuestionId}_survey_next_button_mob_custom`;\n  const submitEl = event.target.closest(selector);\n  if (submitEl) {\n    // Emit email collection event for marketing automation and customer profile integration\n    const emailEl = document.querySelector<HTMLInputElement>(\n      `.tangent_${activeQuizEmailQuestionId}_inputs_container_mob_custom > div > input`);\n\n    type IdentityCapturedEvent = WindowEventMap['identity-captured'];\n\n    const identityCaptured = new CustomEvent<IdentityCapturedEvent['detail']>('identity-captured', {\n      bubbles: true,\n      composed: true,\n      detail: {\n        email: emailEl?.value\n      }\n    });\n\n    submitEl.dispatchEvent(identityCaptured);\n  }\n\n  // The click listener covers the whole quiz, so plenty of clicks that reach us are not answers.\n  // Determine if the click was on a particular option.\n\n  const option = event.target.closest<HTMLElement>('.tangent_options_custom');\n\n  if (!option) {\n    return;\n  }\n\n  type QuizResponseEvent = WindowEventMap['quiz-response'];\n\n  const responseEvent = new CustomEvent<QuizResponseEvent['detail']>('quiz-response', {\n    bubbles: true,\n    composed: true,\n    detail: {\n      event_id: uuidv4(),\n      quiz_id: window.quiz.form_id,\n      name: 'frizz-quiz',\n      vendor: 'tangent',\n      question_id: lastSlideId,\n      answer_text: option.innerText\n    }\n  });\n\n  option.dispatchEvent(responseEvent);\n}\n\n/**\n * Helper method to extract the currently viewed question text from the DOM. This method takes into\n * account the different quiz structures for the selfie and no-selfie versions as well as variations\n * in the DOM when querying for the question text based on the question index. Since there is\n * currently not a reliable way to extract the question text at the time the quiz_progress event is\n * emitted, we will use this method in conjunction with a delayed event emission to ensure that we\n * can extract the correct question text from the DOM when emitting our custom quiz question viewed\n * event for analytics tracking.\n */\nfunction getQuestionText(index: number) {\n  let questionEl;\n  if (index === 0) {\n    questionEl = document.querySelector('.tangent-title-heading');\n  } else {\n    questionEl = document.querySelector('.question-text');\n  }\n\n  return questionEl?.textContent.trim();\n}\n\nfunction onTimeout(currentSlideId: string, current: number) {\n  type QuizViewedEvent = WindowEventMap['quiz-viewed'];\n\n  const questionText = getQuestionText(current);\n  const event = new CustomEvent<QuizViewedEvent['detail']>('quiz-viewed', {\n    bubbles: true,\n    composed: true,\n    detail: {\n      event_id: uuidv4(),\n      question_id: currentSlideId,\n      quiz_id: window.quiz.form_id,\n      vendor: 'tangent',\n      name: 'frizz-quiz',\n      question_text: questionText\n    }\n  });\n\n  dispatchEvent(event);\n}\n\n/**\n * This handles the quiz_progress event emitted by the Tangent quiz library which provides\n * information on the current question index, total number of questions, and the previous and\n * current question GUID. We use this information to emit a hair-quiz-question-viewed event with the\n * question text and to update the quiz progress bar. Additionally, when the user reaches the email\n * question, we pre-fill the email and name fields with known customer information to streamline the\n * quiz completion process.\n */\nfunction onQuizProgress(event: WindowEventMap['quiz_progress']) {\n  const parts = event.detail.split('_');\n  const current = parseInt(parts[0], 10);\n  const total = parseInt(parts[1], 10);\n  const currentSlideId = parts[3];\n  lastSlideId = parts[2];\n\n  if (current !== total) {\n    // Wait for DOM to update with new question text before extracting it for analytics\n    setTimeout(onTimeout, 100, currentSlideId, current);\n  }\n}\n\n/**\n * Handler for the quiz_initialized event which is emitted by Tangent allowing us to emit our own\n * quiz started event which is used for tracking quiz starts in analytics.\n */\nfunction onQuizInitialized(_event: WindowEventMap['quiz_initialized']) {\n  type QuizStartedEvent = WindowEventMap['quiz-started'];\n  const event = new CustomEvent<QuizStartedEvent['detail']>('quiz-started', {\n    bubbles: true,\n    composed: true,\n    detail: {\n      event_id: uuidv4(),\n      quiz_id: window.quiz.form_id,\n      vendor: 'tangent',\n      name: 'frizz-quiz'\n    }\n  });\n\n  activeQuizEmailQuestionId = window.quiz.email_id;\n\n  // Tangent hands us no root element, but the quiz container comes from our own section markup and\n  // wraps everything Tangent renders, so that is the element responsible for the quiz. We dispatch\n  // from it and the event bubbles, so listeners on window still see it.\n  //\n  // Since the Tangent quiz library does not provide a way to track user responses at this time we\n  // must attach click listener to track quiz question responses for analytics. We use event\n  // delegation to listen for clicks on answer options within the container and then extract the\n  // relevant question and answer information to emit in our custom quiz question response event for\n  // analytics tracking.\n  //\n  // If the container ever goes missing we fall back to window and the document, which is what this\n  // used to do unconditionally.\n  const root = document.getElementById('quiz-container');\n\n  if (root) {\n    root.dispatchEvent(event);\n    root.addEventListener('click', onClick, true);\n  } else {\n    dispatchEvent(event);\n    document.addEventListener('click', onClick, true);\n  }\n}\n\naddEventListener('quiz_progress', onQuizProgress);\naddEventListener('quiz_initialized', onQuizInitialized);\n"],"names":["rnds8","Uint8Array","byteToHex","i","push","toString","slice","unsafeStringify","arr","offset","toLowerCase","dist_v4","options","buf","crypto","randomUUID","_ref","_options$random","rnds","random","rng","getRandomValues","length","Error","RangeError","_v4","activeQuizEmailQuestionId","lastSlideId","onClick","event","target","HTMLElement","selector","submitEl","closest","emailEl","document","querySelector","identityCaptured","CustomEvent","bubbles","composed","detail","email","value","dispatchEvent","option","responseEvent","event_id","quiz_id","window","quiz","form_id","name","vendor","question_id","answer_text","innerText","onTimeout","currentSlideId","current","questionText","index","_questionEl","questionEl","textContent","trim","getQuestionText","question_text","addEventListener","parts","split","parseInt","total","setTimeout","_event","email_id","root","getElementById"],"sourceRoot":""}