{"version":3,"file":"site-survey.min.js","sources":["../src/utility/load-styled-element.js","../src/utility/is-mirroring.js","../src/utility/DataFilter.js","../src/customVariables.js","../src/utility/analytics.js","../src/ContextReferrer.js","../src/invitationFeedback.js","../src/feedback.js","../src/utility/click-binder.js","../src/inlineFeedback.js","../src/main.js","../src/site-survey.js","../src/utility/load-script.js"],"sourcesContent":["/**\r\n * Asychronously loads the styles for an element so that it doesn't\r\n * cause a Flash-Of-Unstyled-Content.\r\n * TODO: We have used this in chat fab, we could make this a common library.\r\n * @param {Element} element The element to load styles from.\r\n * This must have a \"data-css-url\" attribute with the path to the CSS as well as the\r\n * \"hidden\" attribute.\r\n * @param {function} initialize A function to execute before making the styled element visible.\r\n * @param {function} error A function to execute if the stylesheet fails to load.\r\n * @param {boolean} show A boolean indicating if this element should automatically be unhidden.\r\n */\r\nconst api = (element, initialize, error, show) => {\r\n if (!document.head || !element) {\r\n return;\r\n }\r\n\r\n const link = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.href = element.getAttribute('data-css-url');\r\n link.onload = () => {\r\n if (initialize) {\r\n initialize();\r\n }\r\n\r\n if (show) {\r\n /* Should be styled and event bound, can show it now. */\r\n element.removeAttribute('hidden');\r\n }\r\n };\r\n /* Note: Does not work for MS IE or Edge: they always call onload, never onerror for links. */\r\n if (error) {\r\n link.onerror = error;\r\n }\r\n\r\n document.head.appendChild(link);\r\n};\r\nexport default api;\r\n","/**\r\n * A utility method to check if the user is being\r\n * mirrored by a customer service agent.\r\n * @param {Location} loc -\r\n * The location to check for mirroring.\r\n * If checking the current webpage, this is generally\r\n * window.location.\r\n * @returns {boolean} TRUE if this is a mirrored session.\r\n */\r\nconst isMirroring = (loc) => {\r\n return loc.hostname.indexOf('mirror') !== -1;\r\n};\r\nexport default isMirroring;\r\n","/**\r\n * A utility class to filter data attributes based on a prefix.\r\n */\r\nexport default class DataFilter {\r\n /**\r\n * Add key/value properties to an object from a dataset\r\n * that match a given prefix filter.\r\n * The prefix will be removed from the resulting keys.\r\n * @param {object} obj -\r\n * The object to extend.\r\n * @param {DOMStringMap} data -\r\n * The dataset to add (matching) property/value pairs from.\r\n * @param {string} filter -\r\n * The filter prefix to extract matching keys with.\r\n * @returns {boolean}\r\n * TRUE if any properties were added.\r\n */\r\n static addProperties(obj, data, filter) {\r\n let added = false;\r\n for (const attributeName in data) {\r\n /* Internet Explorer does not support \"startsWith\" */\r\n if (attributeName.substr(0, filter.length) === filter) {\r\n /* This is implicitly defined, so no need for check. */\r\n obj[attributeName.slice(filter.length)] = data[attributeName];\r\n added = true;\r\n }\r\n }\r\n\r\n return added;\r\n }\r\n}\r\n","import DataFilter from './utility/DataFilter.js';\r\n\r\n/** The class selector for contextual data unique to the page or behaviors. **/\r\nconst SurveyContextClass = 'site-survey-context';\r\n/** The prefix to identify custom variable data attributes in the context. **/\r\nconst customVariablesPrefix = 'customVariables_';\r\n\r\n/**\r\n * Gets the value to set for a variable.\r\n * @param {string} originalValue -\r\n * The existing value set in the variable.\r\n * @param {string} newValue -\r\n * The potential value to update the variable to.\r\n * @returns {string} originalValue if newValue is\r\n * undefined, otherwise newValue.\r\n */\r\nconst getValue = (originalValue, newValue) => {\r\n if (newValue === undefined) {\r\n return originalValue;\r\n }\r\n\r\n return newValue;\r\n};\r\n\r\n/**\r\n * A set of custom reporting variables for the user/page context.\r\n * OpinionLab will serialize the properties in this instance\r\n * into a set of query string parameters to pass to the comment card.\r\n */\r\nexport default class CustomVariables {\r\n /**\r\n * Initializes a new instance of custom reporting\r\n * variables using the current page state.\r\n * @param {string[]} customVariableNames -\r\n * The set of all custom variables that must be set.\r\n * OpinionLab has confirmed we need to send at least an empty string\r\n * for all configured variables on their end.\r\n * @param {string} feedbackType -\r\n * An identifier for which kind of feedback this is used in.\r\n */\r\n constructor(customVariableNames, feedbackType) {\r\n customVariableNames.forEach((element) => {\r\n this[element] = '';\r\n });\r\n\r\n this.feedbackType = getValue(this.feedbackType, feedbackType);\r\n\r\n /*\r\n DESIGN NOTE:\r\n The future direction for client side data will be data attribute driven (ala H.COM methodology)\r\n However, for now not all apps will support this, so there will be two different methods of loading customer data\r\n */\r\n if (window.OpinionLabs) {\r\n this.customerId = getValue(this.customerId, window.OpinionLabs.id);\r\n this.idHash = getValue(this.idHash, window.OpinionLabs.idHash);\r\n this.customerSegment = getValue(this.customerSegment, window.OpinionLabs.segment);\r\n this.secondaryId = getValue(this.secondaryId, window.OpinionLabs.secondaryId);\r\n this.secondaryIdHash = getValue(this.secondaryIdHash, window.OpinionLabs.secondaryIdHash);\r\n }\r\n\r\n const contexts = document.getElementsByClassName(SurveyContextClass);\r\n [].forEach.call(contexts, (context) => {\r\n DataFilter.addProperties(this, context.dataset, customVariablesPrefix);\r\n });\r\n }\r\n}\r\n","/*--------------------------------------------------------------------------------*\\\r\n\r\n Wrapper around analytics functions\r\n\r\n \\*--------------------------------------------------------------------------------*/\r\n\r\n//records the originating adobe page name that the component is launched from\r\n//this allows the components analytic names to be given a context of the originating page\r\nlet launchPageAdobeName = null;\r\n\r\n//check for the adobe 's' object\r\n//if it exists and the originating page name is not set yet, then set it\r\nconst isSCodeReady = () => {\r\n const isReady = typeof s !== 'undefined';\r\n if (!isReady) {\r\n console.warn('No analytics object detected');\r\n }\r\n else if(launchPageAdobeName == null) {\r\n launchPageAdobeName = s.pageName;\r\n }\r\n else {\r\n /* Is already set. */\r\n }\r\n\r\n return isReady;\r\n};\r\n\r\n//given a valid string, split it based on the delimeter\r\nconst toArray = (val, delimiter) => {\r\n if(val && val.length){\r\n return val.split(delimiter);\r\n }\r\n\r\n return [];\r\n};\r\n\r\n//add an events to the request\r\n//optionally for link tracking, add to the adobe configuration property for link events\r\nconst addEvents = (eventsString, isLinkTrack) => {\r\n if(eventsString && eventsString.length){\r\n const events = toArray(eventsString, ',');\r\n if(isLinkTrack) {\r\n //ensure that linkTrackVars exists\r\n s.linkTrackEvents = s.linkTrackEvents || '';\r\n //for each of the events, ensure that the variable name is in the linkTrackVars list\r\n events.forEach((event) => {\r\n if (s.linkTrackEvents.indexOf(event) === -1) {\r\n s.linkTrackEvents += ',' + event;\r\n }\r\n });\r\n }\r\n\r\n s.events = s.events || '';\r\n if(s.events.length) {\r\n s.events += ',';\r\n }\r\n\r\n s.events += events;\r\n }\r\n};\r\n\r\n//parses a string of event key/value pairs into an object graph\r\nconst parseEvarString = (evarString) => {\r\n const retVal = [];\r\n const parts = toArray(evarString, ',');\r\n parts.forEach((part) => {\r\n const evar = toArray(part, '=');\r\n retVal.push({\r\n name: evar[0].trim(),\r\n value: evar.length === 2 ? evar[1]: null\r\n });\r\n });\r\n return retVal;\r\n};\r\n\r\n//add evars to the adobe request\r\n//optionally for link tracking, add to the adobe configuration property for link variables\r\nconst addEvars = (evarString, isLinkTrack) => {\r\n if(!isSCodeReady()) {\r\n return;\r\n }\r\n\r\n if(evarString && evarString.length) {\r\n const evars = parseEvarString(evarString);\r\n if (isLinkTrack) {\r\n //ensure that linkTrackVars exists\r\n s.linkTrackVars = s.linkTrackVars || '';\r\n\r\n //for each of the evars, ensure that the variable name is in the linkTrackVars list\r\n evars.forEach((evar) => {\r\n if (s.linkTrackVars.indexOf(evar.name) === -1) {\r\n s.linkTrackVars += ',' + evar.name;\r\n }\r\n });\r\n }\r\n\r\n evars.forEach(function (evar) {\r\n s[evar.name] = evar.value;\r\n });\r\n }\r\n};\r\n\r\nconst addChannelVars = (pageNameOrig) => {\r\n const delimiter = ':';\r\n const delimiterWithSpace = ': ';\r\n let pageName = pageNameOrig;\r\n\r\n if(pageName && pageName.length) {\r\n pageName = pageName.toLowerCase().replace(/\\s/g, '');\r\n const parts = pageName.split(delimiter);\r\n if (parts.length > 0) {\r\n s.channel = parts[0];\r\n }\r\n\r\n if (parts.length > 1) {\r\n s.prop1 = s.channel + delimiterWithSpace + parts[1];\r\n }\r\n else {\r\n s.prop1 = s.channel;\r\n }\r\n\r\n if (parts.length > 2) {\r\n s.prop2 = s.prop1 + delimiterWithSpace + parts[2];\r\n }\r\n else {\r\n s.prop2 = s.prop1;\r\n }\r\n\r\n if (parts.length > 3) {\r\n s.prop3 = s.prop2 + delimiterWithSpace + parts[3];\r\n }\r\n else {\r\n s.prop3 = s.prop2;\r\n }\r\n\r\n if (parts.length > 4) {\r\n s.prop4 = s.prop3 + delimiterWithSpace + parts[4];\r\n }\r\n else {\r\n s.prop4 = s.prop3;\r\n }\r\n }\r\n};\r\n\r\n//perform any common steps prior to invoking the adobe api\r\nconst prepSCode = (events, evars, isLinkTracking) => {\r\n s.clearVars();\r\n s.usePlugins = false;\r\n addEvents(events, isLinkTracking);\r\n addEvars(evars, isLinkTracking);\r\n};\r\n\r\n//perform any clean up steps after invoking the adobe api\r\nconst resetSCode = () => {\r\n s.usePlugins = true;\r\n s.clearVars();\r\n};\r\n\r\nconst api = {\r\n //register a page view\r\n registerPageView: (pageName, events, evars) => {\r\n if(!isSCodeReady()){\r\n return;\r\n }\r\n\r\n prepSCode(events, evars);\r\n s.pageName = pageName;\r\n addChannelVars(pageName);\r\n s.t();\r\n resetSCode();\r\n },\r\n //register a link click event\r\n registerLinkClick: (linkName, events, evars) => {\r\n if(!isSCodeReady()){\r\n return;\r\n }\r\n\r\n prepSCode(events, evars, true);\r\n s.tl(true,'o', linkName + '|' + launchPageAdobeName);\r\n resetSCode();\r\n },\r\n //get the adobe page name of the containing page\r\n getOriginatingPageName: () => {\r\n if(!isSCodeReady()){\r\n return undefined;\r\n }\r\n\r\n return launchPageAdobeName;\r\n }\r\n};\r\n\r\nexport default api;\r\n","import DataFilter from './utility/DataFilter.js';\r\n\r\n/** The prefix to identify data attributes that should be added to the referrer. **/\r\nconst filter = 'siteSurveyContext_';\r\n\r\n/**\r\n * Return the character to add to a URL\r\n * prior to any new/additional query string.\r\n * @param {string} url -\r\n * The url that may or may not already have a query string.\r\n * @returns {string} The character to append.\r\n */\r\nconst urlSuffix = (url) => {\r\n if (url.indexOf('?') === -1) {\r\n return '?';\r\n }\r\n\r\n return '&';\r\n};\r\n\r\n/**\r\n * Handles generating a referrer URL that contains additional\r\n * context data based on the data attributes.\r\n */\r\nexport default class ContextReferrer {\r\n /**\r\n * Initializes a new instance of ContextReferrer.\r\n */\r\n constructor() {\r\n this.context = {};\r\n }\r\n\r\n /**\r\n * Adds more data to the context.\r\n * Note that existing data with the same key will be\r\n * replaced.\r\n * @param {DOMStringMap} data -\r\n * The set of data to map.\r\n * Only those beginning with the proper prefix will\r\n * be used, others will be ignored.\r\n * @returns {boolean}\r\n * TRUE if any context data were added.\r\n */\r\n addContext(data) {\r\n return DataFilter.addProperties(this.context, data, filter);\r\n }\r\n\r\n /**\r\n * Adds the context data to a given URL.\r\n * @param {string} url -\r\n * The url to append context data to.\r\n * @returns {string} The altered URL.\r\n */\r\n generate(url) {\r\n const keys = Object.keys(this.context);\r\n /* Nothing to add, return the original. */\r\n if (!keys.length) {\r\n return url;\r\n }\r\n\r\n const qs = [];\r\n keys.forEach((key) => {\r\n /* \"ol-\" added to try to avoid any conflicts\r\n with existing params while not making query string TOO long. */\r\n qs.push(`ol-${encodeURIComponent(key)}=${encodeURIComponent(this.context[key])}`);\r\n });\r\n\r\n return `${url}${urlSuffix(url)}${qs.join('&')}`;\r\n }\r\n\r\n /**\r\n * Gets the context data associated with a page.\r\n * @returns {ContextReferrer}\r\n * A populated instance using the page data.\r\n */\r\n static fromPage() {\r\n const referrerContext = new ContextReferrer();\r\n const pageContexts = document.getElementsByClassName('site-survey-context');\r\n [].forEach.call(pageContexts, (pageContext) => {\r\n referrerContext.addContext(pageContext.dataset);\r\n });\r\n return referrerContext;\r\n }\r\n\r\n /**\r\n * Gets the context data associated with a link.\r\n * Page-level data is also added, with the link's\r\n * data taking precedence.\r\n * @param {HTMLElement} clickTarget -\r\n * The link that is being clicked.\r\n * @returns {ContextReferrer}\r\n * A populated instance using the page and link data.\r\n */\r\n static fromLink(clickTarget) {\r\n const referrerContext = ContextReferrer.fromPage();\r\n /* The data will either be on the element or an\r\n * ancestor with injected feedback links.\r\n * It shouldn't be in more than one place:\r\n * we stop once we find some.\r\n */\r\n let elm = clickTarget;\r\n while (elm) {\r\n if (referrerContext.addContext(elm.dataset)) {\r\n return referrerContext;\r\n }\r\n\r\n elm = elm.parentElement;\r\n }\r\n\r\n return referrerContext;\r\n }\r\n}\r\n","/**\r\n * Displays an intercept card for user feedback\r\n * after the user has finished their site visit.\r\n * This wraps the standard OpinionLab implementation into\r\n * a module with the Huntington configuration.\r\n **/\r\nimport isMirroring from './utility/is-mirroring.js';\r\nimport CustomVariables from './customVariables.js';\r\nimport analytics from './utility/analytics.js';\r\nimport ContextReferrer from './ContextReferrer.js';\r\n/**\r\n * Creates a new instance of the global invitation.\r\n * @param {object} o -\r\n * The OpinionLab global object containing class definitions.\r\n * @param {DOMStringMap} config -\r\n * The configuration data.\r\n * @param {string} inviteMarkup -\r\n * An HTML string of the HTML to display for the invite.\r\n * @returns {o.Invitation} A new instance of Invitation.\r\n */\r\nconst createInvitation = (o, config, inviteMarkup) => {\r\n return new o.Invitation({\r\n /* REQUIRED - Asset identification */\r\n pathToAssets: config.pathToAssets,\r\n companyLogo: config.companyLogo,\r\n companySlogan: config.companySlogan,\r\n /* OPTIONAL - Configuration */\r\n responseRate: config.inviteResponseRate,\r\n repromptTime: config.inviteRepromptTime,\r\n pagesHit: config.invitePagesHit,\r\n promptDelay: config.invitePromptDelay,\r\n /* Rewrites the domain to be invite.huntington.com\r\n * (because this is a \"global\" survey) while\r\n * also appending any context data from the page.\r\n */\r\n referrerRewrite: {\r\n replacePattern: ContextReferrer\r\n .fromPage()\r\n .generate(\r\n window.location.href.replace(\r\n /:\\/\\/[^\\/]*/,\r\n '://invite.huntington.com'))\r\n },\r\n customVariables: new CustomVariables(config.customVariableNames.split(','), 'invite'),\r\n callBacks: {\r\n prompt: () => {\r\n analytics.registerPageView(\r\n 'pub: global: survey: invite prompt window',\r\n 'event40',\r\n `eVar53=${analytics.getOriginatingPageName()}`);\r\n },\r\n yesClick: () => {\r\n analytics.registerPageView('pub: global: survey: monitor window');\r\n }\r\n /* Other possible events are \"noClick\" and \"closeClick\". */\r\n },\r\n inviteMarkup\r\n });\r\n};\r\n\r\n/** The underlying invitation feedback singleton. **/\r\nlet invitationFeedback;\r\n\r\n/**\r\n * Initializes the global invitation feedback on the page.\r\n * @param {object} o -\r\n * The OpinionLab global object containing class definitions.\r\n * @param {DOMStringMap} config -\r\n * The configuration data.\r\n */\r\nconst init = (o, config) => {\r\n if (isMirroring(window.location)) {\r\n console.warn('Supress invite feature while mirroring.');\r\n return;\r\n }\r\n\r\n /* Get the HTML for the invite modal.\r\n * Then remove the node (to ensure the id stays unique).\r\n * Lastly, assign the HTML form the node to the Opinion labs variable.\r\n * If the invite div does not exist, skip it all!\r\n */\r\n const inviteDiv = document.getElementById('oo_invitation_prompt');\r\n if (inviteDiv === null) {\r\n console.warn('Skipping invite, no modal div present.');\r\n return;\r\n }\r\n\r\n /* 0% means we don't want to see the invitation.\r\n * This does not quite work when we suppress the invitation\r\n * (by setting it to 0%) on a per-page basis:\r\n * The percentage is set only on the first page and subsequent\r\n * pages read it from a cookie.\r\n * Therefore we need to not invoke the invitation setup at all.\r\n */\r\n if (config.inviteResponseRate <= 0) {\r\n return;\r\n }\r\n\r\n inviteDiv.parentNode.removeChild(inviteDiv);\r\n invitationFeedback = createInvitation(o, config, inviteDiv.outerHTML);\r\n};\r\n\r\n/**\r\n * The public API of this module.\r\n */\r\nconst api = {\r\n init\r\n};\r\nexport default api;\r\n","/** The native size of the icons. **/\r\nconst iconSize = 18;\r\n\r\n/**\r\n * An inline feedback link.\r\n * This manages injecting a new feedback link into parent elements\r\n * that might contain other link structures.\r\n */\r\nclass Feedback {\r\n /**\r\n * Create the feedback element.\r\n * @param {string} text -\r\n * The text of the feedback link.\r\n * @param {string} icon -\r\n The base URL to retrieve the [+] icon(s) from.\r\n * @param {string} type -\r\n * A type that identifies the placement of the feedback link.\r\n * @param {string} cssClass -\r\n * The additional CSS class(es) of the feedback link, if any.\r\n * @returns {HTMLAnchorElement} The link to inject.\r\n */\r\n static createAnchor(text, icon, type, cssClass) {\r\n const anchor = document.createElement('a');\r\n const anchorText = document.createTextNode(text);\r\n anchor.href = '#';\r\n /* These links always open a new window,\r\n so we need this for ADA compliance. */\r\n anchor.title = `${text} (opens in a new window)`;\r\n anchor.setAttribute('data-site-survey-link', type);\r\n if (cssClass) {\r\n anchor.className = cssClass;\r\n }\r\n\r\n const img = document.createElement('img');\r\n /* Marked as presentational so not read by screen readers. */\r\n img.alt = '';\r\n img.className = 'oo_inline_img';\r\n img.src = icon;\r\n /* Another configuration for ADA compliance.\r\n * Note that the CSS stylesheet has been parsed before this,\r\n * so it doesn't actually influence the height.\r\n */\r\n img.height = iconSize;\r\n img.width = iconSize;\r\n anchor.appendChild(img);\r\n anchor.appendChild(anchorText);\r\n\r\n return anchor;\r\n }\r\n\r\n /**\r\n * Create wrapper element with a link.\r\n * @param {HTMLAnchorElement} anchor -\r\n * The anchor to insert inside the wrapper.\r\n * @param {string} wrapperHtml -\r\n * The HTML of a single wrapper element.\r\n * If not defined, no extra wrapper is created.\r\n * @returns {Node} The element to inject.\r\n */\r\n static wrapAnchor(anchor, wrapperHtml) {\r\n if (!wrapperHtml) {\r\n return anchor;\r\n }\r\n\r\n /* A fragment is used so we can create the elements\r\n fully before inserting them. */\r\n const frag = document.createDocumentFragment();\r\n const temp = document.createElement('div');\r\n temp.innerHTML = wrapperHtml;\r\n frag.appendChild(temp.firstChild);\r\n frag.firstChild.appendChild(anchor);\r\n return frag;\r\n }\r\n\r\n /**\r\n * Gets the path to the [+] icon.\r\n * @param {string} pathToAssets -\r\n * The base URL to retrieve the [+] icon(s) from.\r\n * @param {string} iconId -\r\n * An optional identifier for a choice of icon.\r\n * @returns {string} The HREF for an image icon.\r\n */\r\n static iconPath(pathToAssets, iconId) {\r\n let iconIdNorm;\r\n if (iconId) {\r\n /* Recolored icons */\r\n iconIdNorm = `_${iconId}`;\r\n } else {\r\n /* Stock icon. */\r\n iconIdNorm = '';\r\n }\r\n\r\n return `${pathToAssets}oo_icon_retina${iconIdNorm}.gif`;\r\n }\r\n\r\n /**\r\n * Injects an inline Feedback link.\r\n * @param {HTMLElement} parentElement -\r\n * The parent element to inject a feedback link into.\r\n * @param {string} pathToAssets -\r\n * The base URL to retrieve the [+] icon(s) from.\r\n * @param {string} text -\r\n * The text of the feedback link.\r\n */\r\n constructor(parentElement, pathToAssets, text) {\r\n const data = parentElement.dataset;\r\n parentElement.appendChild(\r\n Feedback.wrapAnchor(\r\n Feedback.createAnchor(\r\n text,\r\n Feedback.iconPath(pathToAssets, data.feedbackLinkIconId),\r\n data.feedbackLinkType,\r\n data.feedbackLinkClass),\r\n data.feedbackLinkWrapper));\r\n /* Save this for later comparison. */\r\n this.parentElement = parentElement;\r\n }\r\n}\r\n\r\n/** All currently initialized feedback links. **/\r\nconst feedbacks = [];\r\n\r\n/**\r\n * Check if a given feedback link has already been injected.\r\n * @param {HTMLElement} linkParent -\r\n * The parent element which should contain feedback links.\r\n * @returns {boolean} TRUE if the element already contains\r\n * a feedback link.\r\n */\r\nconst exists = (linkParent) => {\r\n for (let j = 0; j < feedbacks.length; ++j) {\r\n if (linkParent === feedbacks[j].parentElement) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\n/**\r\n * Initializes all feedback links present for a given class.\r\n * This should be safe to be called multiple times.\r\n * @param {string} pathToAssets -\r\n * The base URL to retrieve the [+] icon(s) from.\r\n * @param {HTMLElement} className -\r\n * The class identifier for the parent\r\n * item that will contain feedback links.\r\n * @param {string} text -\r\n * The text of the feedback link. If not set, this method does nothing.\r\n */\r\nconst init = (pathToAssets, className, text) => {\r\n if (!text) {\r\n return;\r\n }\r\n\r\n /* Currently no destroy handling needed. */\r\n const linkParents = document.getElementsByClassName(className);\r\n for (let i = 0; i < linkParents.length; ++i) {\r\n const linkParent = linkParents[i];\r\n if (!exists(linkParent)) {\r\n feedbacks.push(new Feedback(linkParent, pathToAssets, text));\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * The public API of this module.\r\n */\r\nconst api = {\r\n init\r\n};\r\nexport default api;\r\n","/**\r\n * A utility class to bind potential inline feedback link clicks.\r\n */\r\nexport default class ClickBinder {\r\n /**\r\n * Check if an element matches an inline feedback link.\r\n * @param {HTMLElement} element -\r\n * The element that may be a feedback link.\r\n * @returns {boolean} TRUE if the element matches criteria.\r\n */\r\n static matches(element) {\r\n return element.hasAttribute('data-site-survey-link');\r\n }\r\n\r\n /**\r\n * Set up a global binding to the document body for all\r\n * inline feedback link clicks.\r\n * @param {function} callback -\r\n * A function that takes the event and the matching link element.\r\n * This is expected to invoke preventDefault on the link.\r\n * @returns {object} The return result of the callback, if any.\r\n */\r\n static bind(callback) {\r\n document.body.addEventListener('click', (event) => {\r\n /* At this stage, there is no need to traverse all ancestors:\r\n * we only only need to go up one level for the inline image.\r\n */\r\n if (ClickBinder.matches(event.target)) {\r\n return callback(event, event.target);\r\n }\r\n\r\n if (ClickBinder.matches(event.target.parentNode)) {\r\n return callback(event, event.target.parentNode);\r\n }\r\n\r\n return undefined;\r\n });\r\n }\r\n}\r\n","import isMirroring from './utility/is-mirroring.js';\r\nimport feedback from './feedback.js';\r\nimport CustomVariables from './customVariables.js';\r\nimport ClickBinder from './utility/click-binder.js';\r\nimport ContextReferrer from './ContextReferrer.js';\r\n\r\n/*\r\nInline configuration types: 'Footer', 'Help_Center', 'ROL_Dashboard_NML1', 'ROL_Dashboard_NML3', 'ROL_Dashboard_NML5'\r\n*/\r\n\r\n/**\r\n * Launches a survey immediately when\r\n * clicking on an inline feedback link.\r\n * This wraps the standard OpinionLab implementation into\r\n * a module with the Huntington configuration and binding.\r\n **/\r\nclass InlineFeedback {\r\n /**\r\n * Initializes a new instance of the Inline Feedback wrapper.\r\n * @param {object} o -\r\n * The OpinionLab global object containing class definitions.\r\n * @param {DOMStringMap} config -\r\n * The configuration data.\r\n */\r\n constructor(o, config) {\r\n this.o = o;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Injects survey links for the footer and fab.\r\n */\r\n injectSurveyLinks() {\r\n feedback.init(\r\n this.config.pathToAssets,\r\n 'feedback-footer-parent',\r\n this.config.footerFeedbackText);\r\n feedback.init(\r\n this.config.pathToAssets,\r\n 'feedback-fab-parent',\r\n this.config.fabFeedbackText);\r\n }\r\n\r\n /**\r\n * Launches the actual survey.\r\n * @param {Event} event -\r\n * The (click) event that triggered the survey.\r\n * @param {HTMLElement} clickTarget -\r\n * The link that is being clicked.\r\n */\r\n launchOpinionLab(event, clickTarget) {\r\n /* Mirrored customer service users are not allowed to provide feedback\r\n * They are expected to see the links the user would.\r\n */\r\n if (isMirroring(window.location)) {\r\n console.warn('Survey links will not be functional when mirroring a user.');\r\n alert('This action cannot be performed when mirroring a user');\r\n return;\r\n }\r\n\r\n const oo_feedback = new this.o.Ocode({\r\n /* Override the default behavior of sending\r\n * the browser's reported URL to append\r\n * additional contextual data.\r\n */\r\n referrerRewrite: {\r\n replacePattern: ContextReferrer\r\n .fromLink(clickTarget)\r\n .generate(window.location.href)\r\n },\r\n customVariables: new CustomVariables(\r\n this.config.customVariableNames.split(','),\r\n clickTarget.dataset.siteSurveyLink)\r\n });\r\n oo_feedback.show(event);\r\n }\r\n\r\n /**\r\n * Adds an event listener to handle any survey links on the page,\r\n * including those added dynamically later.\r\n */\r\n bindSurveyLinks() {\r\n ClickBinder.bind((event, clickTarget) => {\r\n this.launchOpinionLab(event, clickTarget);\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Initializes the inline invitation feedback links on the page.\r\n * @param {object} o -\r\n * The OpinionLab global object containing class definitions.\r\n * @param {DOMStringMap} config -\r\n * The configuration data.\r\n */\r\nconst init = (o, config) => {\r\n const inlineFeedback = new InlineFeedback(o, config);\r\n inlineFeedback.bindSurveyLinks();\r\n inlineFeedback.injectSurveyLinks();\r\n};\r\n\r\n/**\r\n * The public API of this module.\r\n */\r\nconst api = {\r\n init\r\n};\r\nexport default api;\r\n","/**\r\n * The main entry point for initializing the site survey component.\r\n */\r\nimport SiteSurvey from './site-survey.js';\r\n\r\nconst siteSurvey = new SiteSurvey();\r\n\r\nconst api = {\r\n\r\n};\r\n\r\nexport default api;\r\n","import loadStyledElement from './utility/load-styled-element.js';\r\nimport loadScript from './utility/load-script.js';\r\nimport InvitationFeedback from './invitationFeedback.js';\r\nimport InlineFeedback from './inlineFeedback.js';\r\n\r\n/** The global survey configuration element ID. **/\r\nconst SurveyConfigId = 'site-survey';\r\n\r\nclass SiteSurvey{\r\n\r\n constructor(){\r\n // Ensure that there is a configuration for surveys\r\n const configData = document.getElementById(SurveyConfigId);\r\n if (!configData) {\r\n console.warn('Surveys disabled: No survey configuration present.');\r\n return;\r\n }\r\n\r\n loadStyledElement(configData, () => {\r\n this.config = configData.dataset;\r\n\r\n loadScript(this.config.surveyEngineScript, () => {\r\n this.opinionLab = window.OOo;\r\n if (this.opinionLab === undefined){\r\n console.warn('Surveys disabled: OpinionLab engine script not present.');\r\n return;\r\n }\r\n\r\n InvitationFeedback.init(this.opinionLab, this.config);\r\n InlineFeedback.init(this.opinionLab, this.config);\r\n });\r\n },\r\n () => {\r\n console.error('Cannot configure survey: unable to load stylesheet');\r\n },\r\n false);\r\n }\r\n}\r\n\r\nexport default SiteSurvey;\r\n","/**\r\n * Dynamically loads a Javascript file.\r\n * Optionally, execute code when completed.\r\n * @param {string} url The URL to load the script from.\r\n * @param {function} callback An optional function to execute after the script is loaded.\r\n * @param {function} errorCallback An optional function to execute if the script fails to load.\r\n */\r\nconst loadScript = function(url, callback, errorCallback) {\r\n if (!url || !url.length) {\r\n return;\r\n }\r\n\r\n const script = document.createElement('script');\r\n script.src = url;\r\n if (typeof callback === 'function') {\r\n script.onload = callback;\r\n }\r\n\r\n /* Yes, this works in Internet Explorer. */\r\n if (typeof errorCallback === 'function') {\r\n script.onerror = errorCallback;\r\n }\r\n\r\n document.head.appendChild(script);\r\n};\r\nexport default loadScript;\r\n"],"names":["isMirroring","loc","hostname","indexOf","DataFilter","obj","data","filter","added","attributeName","substr","length","slice","getValue","originalValue","newValue","undefined","CustomVariables","customVariableNames","feedbackType","forEach","element","this","window","OpinionLabs","customerId","id","idHash","customerSegment","segment","secondaryId","secondaryIdHash","contexts","document","getElementsByClassName","call","context","addProperties","dataset","launchPageAdobeName","isSCodeReady","isReady","s","pageName","warn","toArray","val","delimiter","split","addEvars","evarString","isLinkTrack","evars","retVal","part","evar","push","trim","parseEvarString","linkTrackVars","name","value","prepSCode","events","isLinkTracking","clearVars","usePlugins","eventsString","linkTrackEvents","event","resetSCode","api","pageNameOrig","parts","toLowerCase","replace","channel","prop1","prop2","prop3","prop4","t","ContextReferrer","url","keys","Object","qs","key","encodeURIComponent","_this","urlSuffix","join","referrerContext","pageContexts","pageContext","addContext","clickTarget","fromPage","elm","parentElement","o","config","location","inviteDiv","getElementById","inviteResponseRate","parentNode","removeChild","inviteMarkup","Invitation","pathToAssets","companyLogo","companySlogan","inviteRepromptTime","invitePagesHit","invitePromptDelay","generate","href","analytics","createInvitation","outerHTML","Feedback","text","appendChild","wrapAnchor","createAnchor","iconPath","feedbackLinkIconId","feedbackLinkType","feedbackLinkClass","feedbackLinkWrapper","icon","type","cssClass","anchor","createElement","anchorText","createTextNode","title","setAttribute","className","img","alt","src","height","width","wrapperHtml","frag","createDocumentFragment","temp","innerHTML","firstChild","iconId","feedbacks","exists","linkParent","j","linkParents","i","ClickBinder","hasAttribute","callback","body","addEventListener","matches","target","InlineFeedback","footerFeedbackText","fabFeedbackText","Ocode","fromLink","siteSurveyLink","show","bind","launchOpinionLab","inlineFeedback","bindSurveyLinks","injectSurveyLinks","configData","initialize","error","head","link","rel","getAttribute","onload","removeAttribute","onerror","errorCallback","script","surveyEngineScript","opinionLab","OOo"],"mappings":"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"}