{"version":3,"sources":["webpack:///./app/javascript/utilities/showModal.jsx","webpack:///./node_modules/ahoy.js/dist/ahoy.esm.js","webpack:///./app/javascript/utilities/ahoy/trackEvents.jsx","webpack:///./app/javascript/topNavigation/utilities.js","webpack:///./app/javascript/utilities/waitOnBaseData.js","webpack:///./node_modules/focus-visible/dist/focus-visible.js","webpack:///./app/javascript/utilities/podcastPlayback.js","webpack:///./app/javascript/utilities/videoPlayback.js","webpack:///./app/javascript/packs/base.jsx","webpack:///./app/javascript/utilities/runtime.js"],"names":["preactImport","modalImports","WINDOW_MODAL_ID","getPreactImport","showWindowModal","modalContent","contentSelector","onOpen","document","window","modalProps","Promise","all","Modal","render","h","currentModalContainer","getElementById","createElement","setAttribute","body","appendChild","onClose","focusTrapSelector","className","dangerouslySetInnerHTML","__html","querySelector","innerHTML","closeWindowModal","Cookies","name","value","ttl","domain","expires","cookieDomain","date","Date","setTime","getTime","toGMTString","cookie","escape","i","c","nameEQ","ca","split","length","charAt","substring","indexOf","unescape","config","urlPrefix","visitsUrl","eventsUrl","page","platform","useBeacon","startOnReady","trackVisits","cookies","headers","visitParams","withCredentials","visitDuration","visitorDuration","ahoy","Ahoy","configure","options","key","Object","prototype","hasOwnProperty","call","visitId","visitorId","track","callback","$","jQuery","Zepto","isReady","queue","canStringify","JSON","eventQueue","canTrackNow","trackNow","obj","keys","navigator","setCookie","getCookie","destroyCookie","log","message","console","setReady","shift","matchesSelector","element","selector","matches","mozMatchesSelector","msMatchesSelector","oMatchesSelector","webkitMatchesSelector","apply","parentElement","onEvent","eventName","addEventListener","e","matchedElement","target","skip","getClosest","generateId","replace","r","Math","random","toString","saveEventQueue","stringify","csrfToken","meta","content","CSRFProtection","xhr","token","setRequestHeader","sendRequest","url","data","success","ajax","type","contentType","dataType","beforeSend","xhrFields","XMLHttpRequest","header","open","onload","status","send","eventData","event","events","visit_token","visitor_token","trackEvent","ready","id","splice","trackEventNow","param","events_json","sendBeacon","object","FormData","append","serialize","location","pathname","presence","str","eventProperties","cleanObject","tag","this","tagName","toLowerCase","section","attribute","parentNode","hasAttribute","getAttribute","createVisit","getVisitId","getVisitorId","landing_page","href","screen_width","screen","width","screen_height","height","js","referrer","visitParam","push","getVisitToken","getVisitorToken","reset","debug","enabled","properties","time","setTimeout","trackView","additionalProperties","title","propName","trackClicks","undefined","Error","text","textContent","innerText","trim","trackSubmits","trackChanges","parse","start","readyState","trackCommentClicks","elementId","relevantNode","getTrackingNode","dataset","trackingName","trackCreateAccountClicks","version","source","trackingSource","trackingElement","closest","closeHeaderMenu","memberMenu","menuNavButton","classList","remove","clicked","firstItem","initializeMemberMenu","memberTopMenu","userAgent","add","_event","contains","focus","focusFirstItem","activeElement","requestAnimationFrame","openHeaderMenu","isTouchDevice","stopPropagation","secondToLastNavLink","toggleBurgerMenu","leftNavState","getInstantClick","waitTime","resolve","reject","failTimer","clearInterval","timer","setInterval","InstantClick","clearTimeout","initializeMobileMenu","menuTriggers","forEach","trigger","onclick","setCurrentPageIconLink","currentPage","pageEntries","filter","iconLink","blur","removeAttribute","waitOnBaseData","waitingForDataLoad","applyFocusVisiblePolyfill","scope","hadKeyboardEvent","hadFocusVisibleRecently","hadFocusVisibleRecentlyTimeout","inputTypesAllowlist","search","tel","email","password","number","month","week","datetime","isValidFocusTarget","el","nodeName","focusTriggersKeyboardModality","readOnly","isContentEditable","addFocusVisibleClass","removeFocusVisibleClass","onKeyDown","metaKey","altKey","ctrlKey","onPointerDown","onFocus","onBlur","onVisibilityChange","visibilityState","addInitialPointerMoveListeners","onInitialPointerMove","removeInitialPointerMoveListeners","removeEventListener","nodeType","Node","DOCUMENT_FRAGMENT_NODE","host","DOCUMENT_NODE","documentElement","CustomEvent","error","createEvent","initCustomEvent","dispatchEvent","factory","initializePodcastPlayback","podcastPageRecords","podcastLiquidTagrecords","records","deviceType","getById","getByClass","getElementsByClassName","newAudioState","audio","activeEpisode","episode","activePodcast","podcast","html","currentTime","playing","muted","volume","duration","updated","playbackName","currentAudioState","currentState","localStorage","getItem","spinPodcastRecord","customMessage","podcastPlaybackButton","changeStatusMessage","stopRotatingActivePodcastIfExist","saveMediaState","state","newState","setItem","applyOnclickToPodcastBar","playPause","muteUnmute","progress","clientX","percent","innerWidth","Forem","Runtime","podcastMessage","action","seconds","readableDuration","style","goToTime","onchange","updateVolume","speed","parseFloat","playbackRate","rate","changePlaybackRate","updateProgressListener","terminatePodcastBar","bufferValue","buffered","end","updateProgress","loadAudio","getElementsByTagName","src","load","statusBox","startPodcastBar","pausePodcastBar","playAudio","setPlaying","play","then","sendMetadataMessage","metadata","episodeContainer","episodeName","podcastName","podcastImageUrl","ahoyMessage","pause","pauseAudioPlayback","startAudioPlayback","buffer","firstDecimal","floor","sec","min","handlePodcastMessages","detail","namespace","isNativeIOS","isNativeAndroid","msg","ForemMobile","injectNativeMessage","Array","record","episodeSlug","podcastBarAlreadyExistAndPlayingTargetEpisode","loadAndPlayNewPodcast","audioInitialized","initializeMedia","audioContent","initializeVideoPlayback","lastEvent","videoPlayerEvent","isPlaying","article","videoMetadata","videoSource","requestFocus","videoMessage","video_source_url","handleVideoMessages","hms","a","waitingOnJWP","jwplayer","setup","file","mediaid","video_code","image","video_thumbnail_url","playbackRateControls","tracks","video_closed_caption_track_url","label","kind","default","on","seek","initWebPlayer","playerElement","initializePlayer","initializeNav","querySelectorAll","entries","Document","enhancedCommentTextAreaImport","getEnhancedCommentTextAreaImports","initializeEnhancedCommentTextArea","originalTextArea","parentContainer","CommentTextArea","vanillaTextArea","showModal","closeModal","runtime","currentContext","getNavigation","placeholderElement","response","fetch","htmlContent","generatedElement","LogoUploadController","Application","register","Honeybadger","notify","module","foremMobileNamespace","userSessionBroadcast","loadCreatorSettings","currentMedium","currentOS","test","includes","nativeCheck","webkit","messageHandlers","namespaceCheck","AndroidBridge","copyToClipboard","clipboard","writeText","hasOSSpecificModifier","KeyboardEvent","getOSKeyboardModifierKeyString","getCurrentLocale","language"],"mappings":"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","file":"js/base-1e170bce37f7205a68fe.chunk.js","sourcesContent":["// Unique ID applied to modals created using the showWindowModal function\nexport const WINDOW_MODAL_ID = 'window-modal';\n\n// We only import these modules if a user actually triggers a modal. Here we cache them so they are only imported once.\nlet preactImport;\nlet modalImports;\n\nconst getPreactImport = () => {\n if (!preactImport) {\n preactImport = import('preact');\n }\n return preactImport;\n};\n\nconst getModalImports = () => {\n if (!modalImports) {\n modalImports = [import('@crayons/Modal'), getPreactImport()];\n }\n return Promise.all(modalImports);\n};\n\n/**\n * This helper function presents content inside a Preact modal.\n *\n * The modal content may be passed either as:\n * - the actual HTML (using modalContent prop), which will be dropped straight into the modal\n * - a CSS selector (using contentSelector prop), which will be used to locate the HTML content on the current page before dropping it into the modal\n *\n * Only one modal will be presented at any given time. All additional props will be passed directly to the Modal component.\n *\n * @param {Object} args\n * @param {HTMLElement} args.modalContent The HTML to display inside of the modal\n * @param {string} args.contentSelector The CSS query to locate the HTML to be presented in the modal, as an alternative to passing the actual HTML (e.g. '#my-modal-content')\n * @param {Function} args.onOpen A callback function to run when the modal opens. This can be useful, for example, to attach any event listeners to items inside the modal.\n * @param {Object} args.document Allows us to specify which \"document\" is relevant; e.g. use within iframes.\n */\nexport const showWindowModal = async ({\n modalContent,\n contentSelector,\n onOpen,\n document = window.document,\n ...modalProps\n}) => {\n const [{ Modal }, { render, h }] = await getModalImports();\n\n // Guard against two modals being opened at once\n let currentModalContainer = document.getElementById(WINDOW_MODAL_ID);\n if (currentModalContainer) {\n render(null, currentModalContainer);\n } else {\n currentModalContainer = document.createElement('div');\n currentModalContainer.setAttribute('id', WINDOW_MODAL_ID);\n document.body.appendChild(currentModalContainer);\n }\n\n render(\n {\n render(null, currentModalContainer);\n }}\n focusTrapSelector={`#${WINDOW_MODAL_ID}`}\n document={document}\n {...modalProps}\n >\n \n ,\n currentModalContainer,\n );\n\n onOpen?.();\n};\n\n/**\n * This helper function closes any currently open window modal. This can be useful, for example, if your modal contains a \"cancel\" button.\n */\nexport const closeWindowModal = async (document = window.document) => {\n const currentModalContainer = document.getElementById(WINDOW_MODAL_ID);\n if (currentModalContainer) {\n const { render } = await getPreactImport();\n render(null, currentModalContainer);\n }\n};\n","/*!\n * Ahoy.js v0.4.1\n * Simple, powerful JavaScript analytics\n * https://github.com/ankane/ahoy.js\n * MIT License\n */\n\n// https://www.quirksmode.org/js/cookies.html\n\nvar Cookies = {\n set: function (name, value, ttl, domain) {\n var expires = \"\";\n var cookieDomain = \"\";\n if (ttl) {\n var date = new Date();\n date.setTime(date.getTime() + (ttl * 60 * 1000));\n expires = \"; expires=\" + date.toGMTString();\n }\n if (domain) {\n cookieDomain = \"; domain=\" + domain;\n }\n document.cookie = name + \"=\" + escape(value) + expires + cookieDomain + \"; path=/; samesite=lax\";\n },\n get: function (name) {\n var i, c;\n var nameEQ = name + \"=\";\n var ca = document.cookie.split(';');\n for (i = 0; i < ca.length; i++) {\n c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEQ) === 0) {\n return unescape(c.substring(nameEQ.length, c.length));\n }\n }\n return null;\n }\n};\n\nvar config = {\n urlPrefix: \"\",\n visitsUrl: \"/ahoy/visits\",\n eventsUrl: \"/ahoy/events\",\n page: null,\n platform: \"Web\",\n useBeacon: true,\n startOnReady: true,\n trackVisits: true,\n cookies: true,\n cookieDomain: null,\n headers: {},\n visitParams: {},\n withCredentials: false,\n visitDuration: 4 * 60, // default 4 hours\n visitorDuration: 2 * 365 * 24 * 60 // default 2 years\n};\n\nvar ahoy = window.ahoy || window.Ahoy || {};\n\nahoy.configure = function (options) {\n for (var key in options) {\n if (Object.prototype.hasOwnProperty.call(options, key)) {\n config[key] = options[key];\n }\n }\n};\n\n// legacy\nahoy.configure(ahoy);\n\nvar $ = window.jQuery || window.Zepto || window.$;\nvar visitId, visitorId, track;\nvar isReady = false;\nvar queue = [];\nvar canStringify = typeof(JSON) !== \"undefined\" && typeof(JSON.stringify) !== \"undefined\";\nvar eventQueue = [];\n\nfunction visitsUrl() {\n return config.urlPrefix + config.visitsUrl;\n}\n\nfunction eventsUrl() {\n return config.urlPrefix + config.eventsUrl;\n}\n\nfunction isEmpty(obj) {\n return Object.keys(obj).length === 0;\n}\n\nfunction canTrackNow() {\n return (config.useBeacon || config.trackNow) && isEmpty(config.headers) && canStringify && typeof(window.navigator.sendBeacon) !== \"undefined\" && !config.withCredentials;\n}\n\nfunction serialize(object) {\n var data = new FormData();\n for (var key in object) {\n if (Object.prototype.hasOwnProperty.call(object, key)) {\n data.append(key, object[key]);\n }\n }\n return data;\n}\n\n// cookies\n\nfunction setCookie(name, value, ttl) {\n Cookies.set(name, value, ttl, config.cookieDomain || config.domain);\n}\n\nfunction getCookie(name) {\n return Cookies.get(name);\n}\n\nfunction destroyCookie(name) {\n Cookies.set(name, \"\", -1);\n}\n\nfunction log(message) {\n if (getCookie(\"ahoy_debug\")) {\n window.console.log(message);\n }\n}\n\nfunction setReady() {\n var callback;\n while ((callback = queue.shift())) {\n callback();\n }\n isReady = true;\n}\n\nahoy.ready = function (callback) {\n if (isReady) {\n callback();\n } else {\n queue.push(callback);\n }\n};\n\nfunction matchesSelector(element, selector) {\n var matches = element.matches ||\n element.matchesSelector ||\n element.mozMatchesSelector ||\n element.msMatchesSelector ||\n element.oMatchesSelector ||\n element.webkitMatchesSelector;\n\n if (matches) {\n if (matches.apply(element, [selector])) {\n return element;\n } else if (element.parentElement) {\n return matchesSelector(element.parentElement, selector);\n }\n return null;\n } else {\n log(\"Unable to match\");\n return null;\n }\n}\n\nfunction onEvent(eventName, selector, callback) {\n document.addEventListener(eventName, function (e) {\n var matchedElement = matchesSelector(e.target, selector);\n if (matchedElement) {\n var skip = getClosest(matchedElement, \"data-ahoy-skip\");\n if (skip !== null && skip !== \"false\") { return; }\n\n callback.call(matchedElement, e);\n }\n });\n}\n\n// http://beeker.io/jquery-document-ready-equivalent-vanilla-javascript\nfunction documentReady(callback) {\n if (document.readyState === \"interactive\" || document.readyState === \"complete\") {\n setTimeout(callback, 0);\n } else {\n document.addEventListener(\"DOMContentLoaded\", callback);\n }\n}\n\n// https://stackoverflow.com/a/2117523/1177228\nfunction generateId() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = Math.random() * 16 | 0;\n var v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\nfunction saveEventQueue() {\n if (config.cookies && canStringify) {\n setCookie(\"ahoy_events\", JSON.stringify(eventQueue), 1);\n }\n}\n\n// from rails-ujs\n\nfunction csrfToken() {\n var meta = document.querySelector(\"meta[name=csrf-token]\");\n return meta && meta.content;\n}\n\nfunction csrfParam() {\n var meta = document.querySelector(\"meta[name=csrf-param]\");\n return meta && meta.content;\n}\n\nfunction CSRFProtection(xhr) {\n var token = csrfToken();\n if (token) { xhr.setRequestHeader(\"X-CSRF-Token\", token); }\n}\n\nfunction sendRequest(url, data, success) {\n if (canStringify) {\n if ($ && $.ajax) {\n $.ajax({\n type: \"POST\",\n url: url,\n data: JSON.stringify(data),\n contentType: \"application/json; charset=utf-8\",\n dataType: \"json\",\n beforeSend: CSRFProtection,\n success: success,\n headers: config.headers,\n xhrFields: {\n withCredentials: config.withCredentials\n }\n });\n } else {\n var xhr = new XMLHttpRequest();\n xhr.open(\"POST\", url, true);\n xhr.withCredentials = config.withCredentials;\n xhr.setRequestHeader(\"Content-Type\", \"application/json\");\n for (var header in config.headers) {\n if (Object.prototype.hasOwnProperty.call(config.headers, header)) {\n xhr.setRequestHeader(header, config.headers[header]);\n }\n }\n xhr.onload = function () {\n if (xhr.status === 200) {\n success();\n }\n };\n CSRFProtection(xhr);\n xhr.send(JSON.stringify(data));\n }\n }\n}\n\nfunction eventData(event) {\n var data = {\n events: [event]\n };\n if (config.cookies) {\n data.visit_token = event.visit_token;\n data.visitor_token = event.visitor_token;\n }\n delete event.visit_token;\n delete event.visitor_token;\n return data;\n}\n\nfunction trackEvent(event) {\n ahoy.ready(function () {\n sendRequest(eventsUrl(), eventData(event), function () {\n // remove from queue\n for (var i = 0; i < eventQueue.length; i++) {\n if (eventQueue[i].id === event.id) {\n eventQueue.splice(i, 1);\n break;\n }\n }\n saveEventQueue();\n });\n });\n}\n\nfunction trackEventNow(event) {\n ahoy.ready(function () {\n var data = eventData(event);\n var param = csrfParam();\n var token = csrfToken();\n if (param && token) { data[param] = token; }\n // stringify so we keep the type\n data.events_json = JSON.stringify(data.events);\n delete data.events;\n window.navigator.sendBeacon(eventsUrl(), serialize(data));\n });\n}\n\nfunction page() {\n return config.page || window.location.pathname;\n}\n\nfunction presence(str) {\n return (str && str.length > 0) ? str : null;\n}\n\nfunction cleanObject(obj) {\n for (var key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n if (obj[key] === null) {\n delete obj[key];\n }\n }\n }\n return obj;\n}\n\nfunction eventProperties() {\n return cleanObject({\n tag: this.tagName.toLowerCase(),\n id: presence(this.id),\n \"class\": presence(this.className),\n page: page(),\n section: getClosest(this, \"data-section\")\n });\n}\n\nfunction getClosest(element, attribute) {\n for (; element && element !== document; element = element.parentNode) {\n if (element.hasAttribute(attribute)) {\n return element.getAttribute(attribute);\n }\n }\n\n return null;\n}\n\nfunction createVisit() {\n isReady = false;\n\n visitId = ahoy.getVisitId();\n visitorId = ahoy.getVisitorId();\n track = getCookie(\"ahoy_track\");\n\n if (config.cookies === false || config.trackVisits === false) {\n log(\"Visit tracking disabled\");\n setReady();\n } else if (visitId && visitorId && !track) {\n // TODO keep visit alive?\n log(\"Active visit\");\n setReady();\n } else {\n if (!visitId) {\n visitId = generateId();\n setCookie(\"ahoy_visit\", visitId, config.visitDuration);\n }\n\n // make sure cookies are enabled\n if (getCookie(\"ahoy_visit\")) {\n log(\"Visit started\");\n\n if (!visitorId) {\n visitorId = generateId();\n setCookie(\"ahoy_visitor\", visitorId, config.visitorDuration);\n }\n\n var data = {\n visit_token: visitId,\n visitor_token: visitorId,\n platform: config.platform,\n landing_page: window.location.href,\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n js: true\n };\n\n // referrer\n if (document.referrer.length > 0) {\n data.referrer = document.referrer;\n }\n\n for (var key in config.visitParams) {\n if (Object.prototype.hasOwnProperty.call(config.visitParam, key)) {\n data[key] = config.visitParams[key];\n }\n }\n\n log(data);\n\n sendRequest(visitsUrl(), data, function () {\n // wait until successful to destroy\n destroyCookie(\"ahoy_track\");\n setReady();\n });\n } else {\n log(\"Cookies disabled\");\n setReady();\n }\n }\n}\n\nahoy.getVisitId = ahoy.getVisitToken = function () {\n return getCookie(\"ahoy_visit\");\n};\n\nahoy.getVisitorId = ahoy.getVisitorToken = function () {\n return getCookie(\"ahoy_visitor\");\n};\n\nahoy.reset = function () {\n destroyCookie(\"ahoy_visit\");\n destroyCookie(\"ahoy_visitor\");\n destroyCookie(\"ahoy_events\");\n destroyCookie(\"ahoy_track\");\n return true;\n};\n\nahoy.debug = function (enabled) {\n if (enabled === false) {\n destroyCookie(\"ahoy_debug\");\n } else {\n setCookie(\"ahoy_debug\", \"t\", 365 * 24 * 60); // 1 year\n }\n return true;\n};\n\nahoy.track = function (name, properties) {\n // generate unique id\n var event = {\n name: name,\n properties: properties || {},\n time: (new Date()).getTime() / 1000.0,\n id: generateId(),\n js: true\n };\n\n ahoy.ready(function () {\n if (config.cookies && !ahoy.getVisitId()) {\n createVisit();\n }\n\n ahoy.ready(function () {\n log(event);\n\n event.visit_token = ahoy.getVisitId();\n event.visitor_token = ahoy.getVisitorId();\n\n if (canTrackNow()) {\n trackEventNow(event);\n } else {\n eventQueue.push(event);\n saveEventQueue();\n\n // wait in case navigating to reduce duplicate events\n setTimeout(function () {\n trackEvent(event);\n }, 1000);\n }\n });\n });\n\n return true;\n};\n\nahoy.trackView = function (additionalProperties) {\n var properties = {\n url: window.location.href,\n title: document.title,\n page: page()\n };\n\n if (additionalProperties) {\n for (var propName in additionalProperties) {\n if (Object.prototype.hasOwnProperty.call(additionalProperties, propName)) {\n properties[propName] = additionalProperties[propName];\n }\n }\n }\n ahoy.track(\"$view\", properties);\n};\n\nahoy.trackClicks = function (selector) {\n if (selector === undefined) {\n throw new Error(\"Missing selector\");\n }\n onEvent(\"click\", selector, function (e) {\n var properties = eventProperties.call(this, e);\n properties.text = properties.tag === \"input\" ? this.value : (this.textContent || this.innerText || this.innerHTML).replace(/[\\s\\r\\n]+/g, \" \").trim();\n properties.href = this.href;\n ahoy.track(\"$click\", properties);\n });\n};\n\nahoy.trackSubmits = function (selector) {\n if (selector === undefined) {\n throw new Error(\"Missing selector\");\n }\n onEvent(\"submit\", selector, function (e) {\n var properties = eventProperties.call(this, e);\n ahoy.track(\"$submit\", properties);\n });\n};\n\nahoy.trackChanges = function (selector) {\n log(\"trackChanges is deprecated and will be removed in 0.5.0\");\n if (selector === undefined) {\n throw new Error(\"Missing selector\");\n }\n onEvent(\"change\", selector, function (e) {\n var properties = eventProperties.call(this, e);\n ahoy.track(\"$change\", properties);\n });\n};\n\n// push events from queue\ntry {\n eventQueue = JSON.parse(getCookie(\"ahoy_events\") || \"[]\");\n} catch (e) {\n // do nothing\n}\n\nfor (var i = 0; i < eventQueue.length; i++) {\n trackEvent(eventQueue[i]);\n}\n\nahoy.start = function () {\n createVisit();\n\n ahoy.start = function () {};\n};\n\ndocumentReady(function () {\n if (config.startOnReady) {\n ahoy.start();\n }\n});\n\nexport { ahoy as default };\n","import ahoy from 'ahoy.js';\n\n// * Create an ahoy event that will track a click on the\n// * passed in element.\n// *\n// * @param {string} elementId A unique identifier to identify the element that is being tracked\n// */\nexport function trackCommentClicks(elementId) {\n document\n .getElementById(elementId)\n ?.addEventListener('click', ({ target }) => {\n const relevantNode = getTrackingNode(target, '[data-tracking-name]');\n\n if (relevantNode) {\n ahoy.track('Comment section click', {\n page: location.href,\n element: relevantNode.dataset?.trackingName,\n });\n }\n });\n}\n\n// * Create an ahoy event that will track a click on the\n// * passed in element.\n// *\n// * @param {string} elementId A unique identifier to identify the element that is being tracked\n// */\nexport function trackCreateAccountClicks(elementId) {\n document\n .getElementById(elementId)\n ?.addEventListener('click', ({ target }) => {\n const relevantNode = getTrackingNode(target, '[data-tracking-id]');\n if (relevantNode) {\n ahoy.track('Clicked on Create Account', {\n version: 0.1,\n page: location.href,\n source: relevantNode.dataset?.trackingSource,\n });\n }\n });\n}\n\nfunction getTrackingNode(target, trackingElement) {\n // We check for any parent container with a trackingElement attribute, as otherwise\n // SVGs inside buttons can cause events to be missed\n const relevantNode = target.closest(trackingElement);\n return relevantNode;\n}\n","/* global isTouchDevice */\n\nfunction closeHeaderMenu(memberMenu, menuNavButton) {\n menuNavButton.setAttribute('aria-expanded', 'false');\n memberMenu.classList.remove('desktop', 'showing');\n delete memberMenu.dataset.clicked;\n}\n\nconst firstItem = document.getElementById('first-nav-link');\n\nfunction openHeaderMenu(memberMenu, menuNavButton) {\n menuNavButton.setAttribute('aria-expanded', 'true');\n memberMenu.classList.add('showing');\n\n if (!firstItem) {\n return;\n }\n\n // Focus on the first item in the menu\n (function focusFirstItem() {\n if (document.activeElement === firstItem) {\n // The first element has focus\n return;\n }\n\n firstItem.focus();\n // requestAnimationFrame is faster and more reliable than setTimeout\n // https://swizec.com/blog/how-to-wait-for-dom-elements-to-show-up-in-modern-browsers\n window.requestAnimationFrame(focusFirstItem);\n })();\n}\n\n/**\n * Initializes the member navigation menu events.\n *\n * @param {HTMLElement} memberTopMenu The member menu in the top right navigation.\n * @param {HTMLElement} menuNavButton The button to activate the member navigation menu.\n */\nexport function initializeMemberMenu(memberTopMenu, menuNavButton) {\n // Typically using CSS for hovering for the menu is the way to go. But... since we use InstantClick for\n // loading pages, the top header navigation never changes in terms of the DOM references.\n // Because of this, we're using mouse events to mouseover/mouseout on the member's avatar\n // to attach styles to get it to show the menu so that this works on desktop and mobile.\n if (navigator.userAgent === 'DEV-Native-ios') {\n document.body.classList.add('dev-ios-native-body');\n }\n const { classList } = memberTopMenu;\n menuNavButton.addEventListener('click', (_event) => {\n if (classList.contains('showing') && memberTopMenu.dataset.clicked) {\n closeHeaderMenu(memberTopMenu, menuNavButton);\n menuNavButton.focus();\n } else {\n openHeaderMenu(memberTopMenu, menuNavButton);\n memberTopMenu.dataset.clicked = 'clicked';\n }\n });\n\n if (isTouchDevice()) {\n memberTopMenu.addEventListener('focus', (_event) => {\n menuNavButton.setAttribute('aria-expanded', 'true');\n });\n } else {\n memberTopMenu.addEventListener('keyup', (e) => {\n if (e.key === 'Escape' && classList.contains('showing')) {\n closeHeaderMenu(memberTopMenu, menuNavButton);\n menuNavButton.focus();\n }\n });\n }\n\n memberTopMenu\n .querySelector('.crayons-header__menu__dropdown')\n .addEventListener('click', (event) => {\n // There is a click event listener on the body and we do not want\n // this click to be caught by it\n event.stopPropagation();\n\n // Close the menu if the user clicked or touched on mobile a link in the menu.\n closeHeaderMenu(memberTopMenu, menuNavButton);\n menuNavButton.focus();\n });\n\n document.addEventListener('click', (event) => {\n if (event.target.closest('#member-menu-button') === menuNavButton) {\n // The menu navigation button manages it's own click event.\n return;\n }\n\n // Close the menu if the user clicked or touched on mobile a link in the menu.\n closeHeaderMenu(memberTopMenu, menuNavButton);\n });\n\n const secondToLastNavLink = document.getElementById('second-last-nav-link');\n\n document\n .getElementById('last-nav-link')\n .addEventListener('blur', (_event) => {\n // When we tab out of the last link in the member menu, close\n // the menu.\n setTimeout(() => {\n if (document.activeElement === secondToLastNavLink) {\n return;\n }\n\n closeHeaderMenu(memberTopMenu, menuNavButton);\n }, 10);\n });\n}\n\nfunction toggleBurgerMenu() {\n const { leftNavState = 'closed' } = document.body.dataset;\n document.body.dataset.leftNavState =\n leftNavState === 'open' ? 'closed' : 'open';\n}\n\n/**\n * Gets a reference to InstantClick\n *\n * @param {number} [waitTime=2000] The amount of time to wait\n * until giving up waiting for InstantClick to exist\n *\n * @returns {Promise} The global instance of InstantClick.\n */\nexport async function getInstantClick(waitTime = 2000) {\n return new Promise((resolve, reject) => {\n const failTimer = setTimeout(() => {\n clearInterval(timer);\n reject(new Error('Unable to resolve InstantClick'));\n }, waitTime);\n\n const timer = setInterval(() => {\n if (typeof InstantClick !== 'undefined') {\n clearTimeout(failTimer);\n clearInterval(timer);\n resolve(InstantClick);\n }\n });\n });\n}\n\n/**\n * Initializes the hamburger menu for mobile navigation\n *\n * @param {HTMLElement[]} menuTriggers The menuTriggers include the hamburger to open the menu,\n * the close icon to close the menu and the overlay to close the menu.\n */\nexport function initializeMobileMenu(menuTriggers) {\n menuTriggers.forEach((trigger) => {\n trigger.onclick = toggleBurgerMenu;\n });\n}\n\n/**\n * Sets the icon link visually for the current page if the current page\n * is one of the main icon links of the top navigation.\n *\n * @param {string} currentPage\n * @param {[string, HTMLElement][]} pageEntries\n */\nexport function setCurrentPageIconLink(currentPage, pageEntries) {\n pageEntries\n // Filter out nulls (means the user is logged out so most icons are not in the logged out view)\n .filter(([, iconLink]) => iconLink)\n .forEach(([page, iconLink]) => {\n if (currentPage === page) {\n iconLink.blur();\n iconLink.setAttribute('aria-current', 'page');\n } else {\n iconLink.removeAttribute('aria-current');\n }\n });\n}\n","/**\n * A util function to wrap any code that needs to wait until the page has\n * initialized correctly before executing. This is generally the case for\n * packs/components that require `/app/assets/initializers` to execute first,\n * this way you're ensured that global functions/namespaces will be available\n * (i.e. the Runtime class).\n *\n * @returns {Promise} A chainable promise that will fulfill when the page has\n * loaded correctly and all initializers have run.\n */\nexport function waitOnBaseData() {\n return new Promise((resolve) => {\n const waitingForDataLoad = setInterval(() => {\n if (document.body.getAttribute('data-loaded') === 'true') {\n clearInterval(waitingForDataLoad);\n resolve();\n }\n }, 100);\n });\n}\n","(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. ¯\\_(ツ)_/¯\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n","/**\n * This script hunts for podcast's \"Record\" for both the podcast_episode's\n * show page and an article page containing podcast liquid tag. It handles\n * playback and makes sure the record will spin when the podcast is currently\n * playing.\n *\n * The media is initialized (once) and the \"state\" is stored using localStorage.\n * When playback is the website's responsability it's run using the `audio` HTML\n * element. The iOS/Android apps uses a bridging strategy that sends messages\n * using webkit messageHandlers and receives incoming messages through the\n * `contentaudio` element, which allows for native audio playback.\n *\n * The high level functions are the following:\n * - spinPodcastRecord()\n * - findAndApplyOnclickToRecords()\n * - initializeMedia()\n * - currentAudioState()\n * - saveMediaState()\n *\n * The following are useful eslint disables for this file in particular. Because\n * of the way it's wrapped around its own function (own context) we don't have\n * the problem of using a method before it's defined:\n */\n\n/* eslint no-use-before-define: 0 */\n/* eslint no-param-reassign: 0 */\n\nimport ahoy from 'ahoy.js';\n\nexport function initializePodcastPlayback() {\n let deviceType = 'web';\n\n function getById(name) {\n return document.getElementById(name);\n }\n\n function getByClass(name) {\n return document.getElementsByClassName(name);\n }\n\n function newAudioState() {\n const audio = getById('audio');\n window.activeEpisode = audio?.dataset?.episode;\n window.activePodcast = audio?.dataset?.podcast;\n\n return {\n html: getById('audiocontent').innerHTML,\n currentTime: 0,\n playing: false,\n muted: false,\n volume: 1,\n duration: 1,\n updated: new Date().getTime(),\n playbackName: audio?.dataset?.episode,\n };\n }\n\n function currentAudioState() {\n try {\n const currentState = JSON.parse(\n localStorage.getItem('media_playback_state_v3'),\n );\n if (!currentState) {\n return newAudioState();\n }\n return currentState;\n } catch (e) {\n return newAudioState();\n }\n }\n\n function audioExistAndIsPlaying() {\n return getById('audio') && currentAudioState().playing;\n }\n\n function recordExist() {\n return getById(`record-${window.activeEpisode}`);\n }\n\n function spinPodcastRecord(customMessage) {\n if (audioExistAndIsPlaying() && recordExist()) {\n const podcastPlaybackButton = getById(`record-${window.activeEpisode}`);\n podcastPlaybackButton.classList.add('playing');\n podcastPlaybackButton.setAttribute('aria-pressed', 'true');\n changeStatusMessage(customMessage);\n } else {\n stopRotatingActivePodcastIfExist();\n }\n }\n\n function stopRotatingActivePodcastIfExist() {\n if (window.activeEpisode && getById(`record-${window.activeEpisode}`)) {\n const podcastPlaybackButton = getById(`record-${window.activeEpisode}`);\n podcastPlaybackButton.classList.remove('playing');\n podcastPlaybackButton.setAttribute('aria-pressed', 'false');\n window.activeEpisode = undefined;\n }\n }\n\n function findRecords() {\n const podcastPageRecords = getByClass('record-wrapper');\n const podcastLiquidTagrecords = getByClass('podcastliquidtag__record');\n if (podcastPageRecords.length > 0) {\n return podcastPageRecords;\n }\n return podcastLiquidTagrecords;\n }\n\n function saveMediaState(state) {\n const currentState = state || currentAudioState();\n const newState = newAudioState();\n newState.currentTime = currentState.currentTime;\n newState.playing = currentState.playing;\n newState.muted = currentState.muted;\n newState.volume = currentState.volume;\n newState.duration = currentState.duration;\n localStorage.setItem('media_playback_state_v3', JSON.stringify(newState));\n return newState;\n }\n\n function applyOnclickToPodcastBar(audio) {\n const currentState = currentAudioState();\n getById('barPlayPause').onclick = function () {\n playPause(audio);\n };\n getById('mutebutt').onclick = function () {\n muteUnmute(audio);\n };\n getById('volbutt').onclick = function () {\n muteUnmute(audio);\n };\n getById('bufferwrapper').onclick = function (e) {\n goToTime(e, audio);\n };\n getById('volumeslider').value = currentState.volume * 100;\n getById('volumeslider').onchange = function (e) {\n updateVolume(e, audio);\n };\n getById('speed').onclick = function () {\n changePlaybackRate(audio);\n };\n getById('closebutt').onclick = function () {\n terminatePodcastBar(audio);\n };\n }\n\n function podcastBarAlreadyExistAndPlayingTargetEpisode(episodeSlug) {\n return getById('audiocontent').innerHTML.indexOf(`${episodeSlug}`) !== -1;\n }\n\n function updateProgressListener(audio) {\n return () => {\n let bufferValue = 0;\n if (audio.currentTime > 0) {\n const bufferEnd = audio.buffered.end(audio.buffered.length - 1);\n bufferValue = (bufferEnd / audio.duration) * 100;\n }\n updateProgress(audio.currentTime, audio.duration, bufferValue);\n };\n }\n\n function loadAudio(audio) {\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'load',\n url: audio.getElementsByTagName('source')[0].src,\n });\n } else {\n audio.load();\n }\n }\n\n function loadAndPlayNewPodcast(episodeSlug) {\n getById('audiocontent').innerHTML = getById(\n `hidden-audio-${episodeSlug}`,\n ).innerHTML;\n const audio = getById('audio');\n audio.addEventListener('timeupdate', updateProgressListener(audio), false);\n loadAudio(audio);\n playPause(audio);\n applyOnclickToPodcastBar(audio);\n }\n\n function findAndApplyOnclickToRecords() {\n const records = findRecords();\n Array.prototype.forEach.call(records, (record) => {\n const episodeSlug = record.getAttribute('data-episode');\n const togglePodcastState = () => {\n if (podcastBarAlreadyExistAndPlayingTargetEpisode(episodeSlug)) {\n const audio = getById('audio');\n if (audio) {\n playPause(audio);\n }\n } else {\n stopRotatingActivePodcastIfExist();\n loadAndPlayNewPodcast(episodeSlug);\n }\n };\n record.addEventListener('click', togglePodcastState);\n });\n }\n\n function changePlaybackRate(audio) {\n const currentState = currentAudioState();\n const el = getById('speed');\n const speed = parseFloat(el.getAttribute('data-speed'));\n if (speed === 2) {\n el.setAttribute('data-speed', 0.5);\n el.innerHTML = '0.5x';\n currentState.playbackRate = 0.5;\n } else {\n el.setAttribute('data-speed', speed + 0.5);\n el.innerHTML = `${speed + 0.5}x`;\n currentState.playbackRate = speed + 0.5;\n }\n saveMediaState(currentState);\n\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'rate',\n rate: currentState.playbackRate.toString(),\n });\n } else {\n audio.playbackRate = currentState.playbackRate;\n }\n }\n\n function changeStatusMessage(message) {\n const currentState = currentAudioState();\n const statusBox = getById(`status-message-${currentState.playbackName}`);\n if (statusBox) {\n if (message) {\n statusBox.classList.add('showing');\n statusBox.innerHTML = message;\n } else {\n statusBox.classList.remove('showing');\n }\n } else if (\n message === 'initializing...' &&\n getByClass('status-message')[0]\n ) {\n getByClass('status-message')[0].innerHTML = message;\n }\n }\n\n function startPodcastBar() {\n getById('barPlayPause').classList.add('playing');\n getById('progressBar').classList.add('playing');\n getById('animated-bars').classList.add('playing');\n }\n\n function pausePodcastBar() {\n getById('barPlayPause').classList.remove('playing');\n getById('animated-bars').classList.remove('playing');\n }\n\n function playAudio(audio) {\n return new Promise((resolve, reject) => {\n const currentState = currentAudioState();\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'play',\n url: audio.getElementsByTagName('source')[0].src,\n seconds: currentState.currentTime.toString(),\n });\n setPlaying(true);\n resolve();\n } else {\n audio.currentTime = currentState.currentTime;\n audio\n .play()\n .then(() => {\n setPlaying(true);\n resolve();\n })\n .catch(() => {\n setPlaying(false);\n reject();\n });\n }\n });\n }\n\n function fetchMetadataString() {\n let episodeContainer = getByClass('podcast-episode-container')[0];\n if (episodeContainer === undefined) {\n episodeContainer = getByClass('podcastliquidtag')[0];\n }\n return episodeContainer.dataset.meta;\n }\n\n function sendMetadataMessage() {\n if (window.Forem.Runtime.podcastMessage) {\n try {\n const metadata = JSON.parse(fetchMetadataString());\n window.Forem.Runtime.podcastMessage({\n action: 'metadata',\n episodeName: metadata.episodeName,\n podcastName: metadata.podcastName,\n podcastImageUrl: metadata.podcastImageUrl,\n });\n } catch (e) {\n console.log('Unable to load Podcast Episode metadata', e); // eslint-disable-line no-console\n }\n }\n }\n\n function startAudioPlayback(audio) {\n sendMetadataMessage();\n\n playAudio(audio)\n .then(() => {\n spinPodcastRecord();\n startPodcastBar();\n })\n .catch(() => {\n playAudio(audio);\n setTimeout(() => {\n spinPodcastRecord('initializing...');\n startPodcastBar();\n }, 5);\n });\n }\n\n function pauseAudioPlayback(audio) {\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({ action: 'pause' });\n } else {\n audio.pause();\n }\n setPlaying(false);\n stopRotatingActivePodcastIfExist();\n pausePodcastBar();\n }\n\n function ahoyMessage(action) {\n const properties = {\n action,\n episode: window.activeEpisode,\n podcast: window.activePodcast,\n deviceType,\n };\n ahoy.track('Podcast Player Streaming', properties);\n }\n\n function playPause(audio) {\n let currentState = currentAudioState();\n if (currentState.playbackName != getById('audio').dataset.episode) {\n currentState = newAudioState();\n saveMediaState(currentState);\n }\n\n if (!currentState.playing) {\n ahoyMessage('play');\n changeStatusMessage(null);\n startAudioPlayback(audio);\n } else {\n ahoyMessage('pause');\n pauseAudioPlayback(audio);\n changeStatusMessage(null);\n }\n spinPodcastRecord();\n }\n\n function muteUnmute(audio) {\n const currentState = currentAudioState();\n getById('mutebutt').classList.add(\n currentState.muted ? 'hidden' : 'showing',\n );\n getById('volumeindicator').classList.add(\n currentState.muted ? 'showing' : 'hidden',\n );\n getById('mutebutt').classList.remove(\n currentState.muted ? 'showing' : 'hidden',\n );\n getById('volumeindicator').classList.remove(\n currentState.muted ? 'hidden' : 'showing',\n );\n\n currentState.muted = !currentState.muted;\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'muted',\n muted: currentState.muted.toString(),\n });\n } else {\n audio.muted = currentState.muted;\n }\n saveMediaState(currentState);\n }\n\n function updateVolume(e, audio) {\n const currentState = currentAudioState();\n currentState.volume = e.target.value / 100;\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'volume',\n volume: currentState.volume,\n });\n } else {\n audio.volume = currentState.volume;\n }\n saveMediaState(currentState);\n }\n\n function updateProgress(currentTime, duration, bufferValue) {\n const progress = getById('progress');\n const buffer = getById('buffer');\n const time = getById('time');\n let value = 0;\n const firstDecimal = currentTime - Math.floor(currentTime);\n if (currentTime > 0) {\n value = Math.floor((100.0 / duration) * currentTime);\n if (firstDecimal < 0.4) {\n // Rewrite to mediaState storage every few beats.\n const currentState = currentAudioState();\n currentState.duration = duration;\n currentState.currentTime = currentTime;\n saveMediaState(currentState);\n }\n }\n if (progress && time && currentTime > 0) {\n progress.style.width = `${value}%`;\n buffer.style.width = `${bufferValue}%`;\n time.innerHTML = `${readableDuration(currentTime)} / ${readableDuration(\n duration,\n )}`;\n }\n }\n\n function goToTime(e, audio) {\n const currentState = currentAudioState();\n const progress = getById('progress');\n const time = getById('time');\n if (e.clientX > 128) {\n const percent = (e.clientX - 128) / (window.innerWidth - 133);\n currentState.currentTime = currentState.duration * percent; // jumps to 29th secs\n\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({\n action: 'seek',\n seconds: currentState.currentTime.toString(),\n });\n } else {\n audio.currentTime = currentState.currentTime;\n }\n\n const currentTime = readableDuration(currentState.currentTime);\n const duration = readableDuration(currentState.duration);\n time.innerHTML = `${currentTime} / ${duration}`;\n progress.style.width = `${percent * 100.0}%`;\n }\n }\n\n function readableDuration(seconds) {\n let sec = Math.floor(seconds);\n let min = Math.floor(sec / 60);\n min = min >= 10 ? min : `0${min}`;\n sec = Math.floor(sec % 60);\n sec = sec >= 10 ? sec : `0${sec}`;\n return `${min}:${sec}`;\n }\n\n function terminatePodcastBar(audio) {\n audio.removeEventListener(\n 'timeupdate',\n updateProgressListener(audio),\n false,\n );\n getById('audiocontent').innerHTML = '';\n stopRotatingActivePodcastIfExist();\n saveMediaState(newAudioState());\n if (window.Forem.Runtime.podcastMessage) {\n window.Forem.Runtime.podcastMessage({ action: 'terminate' });\n }\n }\n\n function handlePodcastMessages(event) {\n const message = JSON.parse(event.detail);\n if (message.namespace !== 'podcast') {\n return;\n }\n\n const currentState = currentAudioState();\n switch (message.action) {\n case 'init':\n getById('time').innerHTML = 'initializing...';\n currentState.currentTime = 0;\n break;\n case 'play':\n ahoyMessage('play');\n spinPodcastRecord();\n startPodcastBar();\n break;\n case 'pause':\n ahoyMessage('pause');\n setPlaying(false);\n stopRotatingActivePodcastIfExist();\n pausePodcastBar();\n break;\n case 'tick':\n currentState.currentTime = message.currentTime;\n currentState.duration = message.duration;\n updateProgress(currentState.currentTime, currentState.duration, 100);\n break;\n default:\n console.log('Unrecognized message: ', message); // eslint-disable-line no-console\n }\n\n saveMediaState(currentState);\n }\n\n // When window.Forem.Runtime.podcastMessage is undefined we need to execute web logic\n function initRuntime() {\n if (window.Forem.Runtime.isNativeIOS('podcast')) {\n deviceType = 'iOS';\n } else if (window.Forem.Runtime.isNativeAndroid('podcastMessage')) {\n deviceType = 'Android';\n }\n\n if (deviceType !== 'web') {\n window.Forem.Runtime.podcastMessage = (msg) => {\n window.ForemMobile.injectNativeMessage('podcast', msg);\n };\n }\n }\n\n function initializeMedia() {\n const currentState = currentAudioState();\n document.getElementById('audiocontent').innerHTML = currentState.html;\n const audio = getById('audio');\n if (audio === undefined || audio === null) {\n window.Forem.audioInitialized = false;\n return;\n }\n if (window.Forem.Runtime.podcastMessage) {\n audio.currentTime = currentState.currentTime || 0;\n }\n loadAudio(audio);\n if (currentState.playing) {\n playAudio(audio).catch(() => {\n pausePodcastBar();\n });\n }\n setTimeout(() => {\n audio.addEventListener(\n 'timeupdate',\n updateProgressListener(audio),\n false,\n );\n document.addEventListener('ForemMobile', handlePodcastMessages);\n }, 500);\n applyOnclickToPodcastBar(audio);\n }\n\n function setPlaying(playing) {\n const currentState = currentAudioState();\n currentState.playing = playing;\n saveMediaState(currentState);\n }\n\n initRuntime();\n spinPodcastRecord();\n findAndApplyOnclickToRecords();\n if (!window.Forem.audioInitialized) {\n window.Forem.audioInitialized = true;\n initializeMedia();\n }\n const audio = getById('audio');\n const audioContent = getById('audiocontent');\n if (audio && audioContent && audioContent.innerHTML.length < 25) {\n // audio not already loaded\n loadAudio(audio);\n }\n}\n","/**\n * This script hunts for video tags and initializes the correct player\n * depending on the platform:\n * - web: jwplayer\n * - iOS/Android: Native player\n *\n * Once jwplayer is initialized there's no follow up actions to be taken.\n * Mobile Native players send back information into the DOM in order to\n * interact and update the UI, therefore a MutationObserver is registered.\n */\n\n/* eslint no-use-before-define: 0 */\n/* eslint no-param-reassign: 0 */\n/* eslint no-useless-escape: 0 */\n/* global jwplayer */\n\nimport ahoy from 'ahoy.js';\n\nexport function initializeVideoPlayback() {\n let currentTime = '0';\n let deviceType = 'web';\n let lastEvent = '';\n\n function getById(name) {\n return document.getElementById(name);\n }\n\n function timeToSeconds(hms) {\n let a;\n if (hms.length < 3) {\n return hms;\n } else if (hms.length < 6) {\n a = hms.split(':');\n return (hms = +a[0] * 60 + +a[1]);\n }\n a = hms.split(':');\n return (hms = +a[0] * 60 * 60 + +a[1] * 60 + +a[2]);\n }\n\n function videoPlayerEvent(isPlaying) {\n // jwtplayer tends to send multiple 'play' actions. This check makes sure\n // we're not tracking repeated 'play' events for a single interaction.\n const eventName = isPlaying ? 'play' : 'pause';\n if (lastEvent === eventName) {\n return;\n }\n lastEvent = eventName;\n\n const metadata = videoMetadata(getById('video-player-source'));\n const properties = {\n article: metadata.id,\n deviceType,\n action: eventName,\n };\n ahoy.track('Video Player Streaming', properties);\n }\n\n function initWebPlayer(seconds, metadata) {\n const waitingOnJWP = setInterval(() => {\n if (typeof jwplayer !== 'undefined') {\n clearInterval(waitingOnJWP);\n const playerInstance = jwplayer(`video-player-${metadata.id}`);\n playerInstance.setup({\n file: metadata.video_source_url,\n mediaid: metadata.video_code,\n image: metadata.video_thumbnail_url,\n playbackRateControls: true,\n tracks: [\n {\n file: metadata.video_closed_caption_track_url,\n label: 'English',\n kind: 'captions',\n default: false,\n },\n ],\n });\n if (seconds) {\n jwplayer().on('firstFrame', () => {\n jwplayer().seek(seconds);\n });\n jwplayer().on('play', () => {\n videoPlayerEvent(true);\n });\n jwplayer().on('pause', () => {\n videoPlayerEvent(false);\n });\n }\n }\n }, 2);\n }\n\n function videoMetadata(videoSource) {\n try {\n return JSON.parse(videoSource.dataset.meta);\n } catch (e) {\n console.log('Unable to load Podcast Episode metadata', e); // eslint-disable-line no-console\n }\n }\n\n function requestFocus() {\n const metadata = videoMetadata(videoSource);\n\n getById('pause-butt').classList.add('active');\n getById('play-butt').classList.remove('active');\n\n window.Forem.Runtime.videoMessage({\n action: 'play',\n url: metadata.video_source_url,\n seconds: currentTime,\n });\n\n videoPlayerEvent(true);\n }\n\n function handleVideoMessages(event) {\n const message = JSON.parse(event.detail);\n if (message.namespace !== 'video') {\n return;\n }\n\n switch (message.action) {\n case 'play':\n getById('pause-butt').classList.add('active');\n getById('play-butt').classList.remove('active');\n videoPlayerEvent(true);\n break;\n case 'pause':\n getById('pause-butt').classList.remove('active');\n getById('play-butt').classList.add('active');\n videoPlayerEvent(false);\n break;\n case 'tick':\n currentTime = message.currentTime;\n break;\n default:\n console.log('Unrecognized message: ', message); // eslint-disable-line no-console\n }\n }\n\n function initializePlayer(videoSource) {\n const seconds = timeToSeconds('0');\n const metadata = videoMetadata(videoSource);\n\n if (window.Forem.Runtime.isNativeIOS('video')) {\n deviceType = 'iOS';\n } else if (window.Forem.Runtime.isNativeAndroid('videoMessage')) {\n deviceType = 'Android';\n } else {\n // jwplayer is initialized and no further interaction is needed\n initWebPlayer(seconds, metadata);\n return;\n }\n\n window.Forem.Runtime.videoMessage = (msg) => {\n window.ForemMobile.injectNativeMessage('video', msg);\n };\n\n const playerElement = getById(`video-player-${metadata.id}`);\n playerElement.addEventListener('click', requestFocus);\n\n playerElement.classList.add('native');\n getById('play-butt').classList.add('active');\n\n document.addEventListener('ForemMobile', handleVideoMessages);\n\n currentTime = `${seconds}`;\n }\n\n // If an video player element is found initialize it\n const videoSource = getById('video-player-source');\n if (videoSource !== null) {\n initializePlayer(videoSource);\n }\n}\n","import 'focus-visible';\nimport {\n initializeMobileMenu,\n setCurrentPageIconLink,\n initializeMemberMenu,\n} from '../topNavigation/utilities';\nimport { waitOnBaseData } from '../utilities/waitOnBaseData';\nimport { initializePodcastPlayback } from '../utilities/podcastPlayback';\nimport { initializeVideoPlayback } from '../utilities/videoPlayback';\nimport { trackCreateAccountClicks } from '@utilities/ahoy/trackEvents';\nimport { showWindowModal, closeWindowModal } from '@utilities/showModal';\nimport * as Runtime from '@utilities/runtime';\n\nDocument.prototype.ready = new Promise((resolve) => {\n if (document.readyState !== 'loading') {\n return resolve();\n }\n document.addEventListener('DOMContentLoaded', () => resolve());\n return null;\n});\n\n// Namespace for functions which need to be accessed in plain JS initializers\nwindow.Forem = {\n audioInitialized: false,\n preactImport: undefined,\n getPreactImport() {\n if (!this.preactImport) {\n this.preactImport = import('preact');\n }\n return this.preactImport;\n },\n enhancedCommentTextAreaImport: undefined,\n getEnhancedCommentTextAreaImports() {\n if (!this.enhancedCommentTextAreaImport) {\n this.enhancedCommentTextAreaImport = import(\n './CommentTextArea/CommentTextArea'\n );\n }\n return Promise.all([\n this.enhancedCommentTextAreaImport,\n this.getPreactImport(),\n ]);\n },\n initializeEnhancedCommentTextArea: async (originalTextArea) => {\n const parentContainer = originalTextArea.parentElement;\n\n const alreadyInitialized =\n parentContainer.classList.contains('c-autocomplete');\n\n if (alreadyInitialized) {\n return;\n }\n\n const [{ CommentTextArea }, { render, h }] =\n await window.Forem.getEnhancedCommentTextAreaImports();\n\n render(\n ,\n parentContainer,\n originalTextArea,\n );\n },\n showModal: showWindowModal,\n closeModal: () => closeWindowModal(),\n Runtime,\n};\n\ninitializePodcastPlayback();\ninitializeVideoPlayback();\nInstantClick.on('change', () => {\n initializePodcastPlayback();\n initializeVideoPlayback();\n});\n\n// Initialize data-runtime context to the body data-attribute\ndocument.body.dataset.runtime = window.Forem.Runtime.currentContext();\n\nfunction getPageEntries() {\n return Object.entries({\n 'notifications-index': document.getElementById('notifications-link'),\n 'moderations-index': document.getElementById('moderation-link'),\n 'articles_search-index': document.getElementById('search-link'),\n });\n}\n\n/**\n * Initializes the left hand side hamburger menu\n */\nfunction initializeNav() {\n const { currentPage } = document.getElementById('page-content').dataset;\n const menuTriggers = [\n ...document.querySelectorAll('.js-hamburger-trigger, .hamburger a'),\n ];\n\n setCurrentPageIconLink(currentPage, getPageEntries());\n initializeMobileMenu(menuTriggers);\n}\n\nconst memberMenu = document.getElementById('crayons-header__menu');\nconst menuNavButton = document.getElementById('member-menu-button');\n\nif (memberMenu) {\n initializeMemberMenu(memberMenu, menuNavButton);\n}\n\n/**\n * Fetches the html for the navigation_links from an endpoint and dynamically insterts it in the DOM.\n */\nasync function getNavigation() {\n const placeholderElement = document.getElementsByClassName(\n 'js-navigation-links-container',\n )[0];\n\n if (placeholderElement.innerHTML.trim() === '') {\n const response = await window.fetch(`/async_info/navigation_links`);\n const htmlContent = await response.text();\n\n const generatedElement = document.createElement('div');\n generatedElement.innerHTML = htmlContent;\n\n placeholderElement.appendChild(generatedElement);\n }\n}\n\n// Initialize when asset pipeline (sprockets) initializers have executed\nwaitOnBaseData()\n .then(() => {\n InstantClick.on('change', () => {\n initializeNav();\n });\n\n if (Runtime.currentMedium() === 'ForemWebView') {\n // Dynamic import of the namespace\n import('../mobile/foremMobile.js').then((module) => {\n // Load the namespace\n window.ForemMobile = module.foremMobileNamespace();\n // Run the first session\n window.ForemMobile.userSessionBroadcast();\n });\n }\n })\n .catch((error) => {\n Honeybadger.notify(error);\n });\n\n// we need to call initializeNav here for the initial page load\ninitializeNav();\n\nasync function loadCreatorSettings() {\n try {\n const [{ LogoUploadController }, { Application }] = await Promise.all([\n import('@admin/controllers/logo_upload_controller'),\n import('@hotwired/stimulus'),\n ]);\n\n const application = Application.start();\n application.register('logo-upload', LogoUploadController);\n } catch (error) {\n Honeybadger.notify(\n `Error loading the creator settings controller: ${error.message}`,\n );\n }\n}\n\nif (document.location.pathname === '/admin/creator_settings/new') {\n loadCreatorSettings();\n}\n\ndocument.ready.then(() => {\n const hamburgerTrigger = document.getElementsByClassName(\n 'js-hamburger-trigger',\n )[0];\n hamburgerTrigger.addEventListener('click', getNavigation);\n});\n\ntrackCreateAccountClicks('authentication-hamburger-actions');\ntrackCreateAccountClicks('authentication-top-nav-actions');\ntrackCreateAccountClicks('comments-locked-cta');\n","/**\n * This function returns a string combining the current Medium and OS\n * that represents the current Context where the app is running.\n *\n * @returns {String} \"Medium-OS\", for example \"Browser-Android\"\n */\nexport const currentContext = () => `${currentMedium()}-${currentOS()}`;\n\n/**\n * This function returns a string that represents the current Medium where\n * the app is currently running. The currently supported mediums are Browser,\n * and ForemWebView.\n *\n * @returns {String} One of the supported Mediums\n */\nexport const currentMedium = () =>\n /ForemWebView/i.test(navigator.userAgent) ? 'ForemWebView' : 'Browser';\n\n/**\n * This function returns a string that represents the current OS where the app\n * is currently running. The currently supported Operating Systems are\n * Windows, Linux, macOS, Android and iOS.\n *\n * @returns {String} One of the supported Operating Systems or 'Unsupported'\n */\nexport const currentOS = () => {\n const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'];\n const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'];\n const iosPlatforms = ['iPhone', 'iPad', 'iPod'];\n\n if (macosPlatforms.includes(window.navigator.platform)) {\n return 'macOS';\n } else if (iosPlatforms.includes(window.navigator.platform)) {\n return 'iOS';\n } else if (windowsPlatforms.includes(window.navigator.platform)) {\n return 'Windows';\n } else if (/Android/i.test(window.navigator.userAgent)) {\n return 'Android';\n } else if (/Linux/i.test(window.navigator.platform)) {\n return 'Linux';\n }\n\n return 'Unsupported';\n};\n\n/**\n * Checks the device for iOS (webkit) native feature support\n *\n * @function isNativeIOS\n * @param {string} namespace Specifies support for a specific feature\n * (i.e. video, podcast, etc)\n * @returns {boolean} true if current environment support native features\n */\nexport const isNativeIOS = (namespace = null) => {\n const nativeCheck =\n /DEV-Native-ios|ForemWebView/i.test(navigator.userAgent) &&\n window &&\n window.webkit &&\n window.webkit.messageHandlers;\n\n let namespaceCheck = true;\n if (nativeCheck && namespace) {\n namespaceCheck = window.webkit.messageHandlers[namespace] != undefined;\n }\n\n return nativeCheck && namespaceCheck;\n};\n\n/**\n * Checks the device for Android native feature support\n *\n * @function isNativeAndroid\n * @param {string} namespace Specifies support for a specific feature\n * (i.e. videoMessage, podcastMessage, etc)\n * @returns {boolean} true if current environment support native features\n */\nexport const isNativeAndroid = (namespace = null) => {\n const nativeCheck =\n /DEV-Native-android|ForemWebView/i.test(navigator.userAgent) &&\n typeof AndroidBridge !== 'undefined';\n\n let namespaceCheck = true;\n if (nativeCheck && namespace) {\n namespaceCheck = AndroidBridge[namespace] != undefined;\n }\n\n return nativeCheck && namespaceCheck;\n};\n\n/**\n * This function copies text to clipboard taking in consideration all\n * supported platforms.\n *\n * @param {string} text to be copied to the clipboard\n *\n * @returns {Promise} Resolves when successful in copying to clipboard\n */\nexport const copyToClipboard = (text) => {\n return new Promise((resolve, reject) => {\n if (isNativeAndroid('copyToClipboard')) {\n AndroidBridge.copyToClipboard(text);\n resolve();\n } else if (navigator.clipboard != null) {\n navigator.clipboard\n .writeText(text)\n .then(() => {\n resolve();\n })\n .catch((e) => {\n reject(e);\n });\n } else {\n reject('Unable to copy the text. Try reloading the page');\n }\n });\n};\n\n/**\n * Returns true if the supplied KeyboardEvent includes the OS-specific\n * modifier key. For example, the Cmd key on Apple platforms or the Ctrl key\n * on others.\n *\n * @param {KeyboardEvent} The event to check for the OS-specific modifier key\n *\n * @returns {Boolean} true if the event was fired with the OS-specific\n * modifier key, false otherwise. Also returns false if\n * the event is not a KeyboardEvent.\n */\nexport const hasOSSpecificModifier = (event) => {\n if (!(event instanceof KeyboardEvent)) {\n return false;\n }\n\n if (navigator.userAgent.indexOf('Mac OS X') >= 0) {\n return event.metaKey;\n }\n return event.ctrlKey;\n};\n\n/**\n * Returns a string representation of the expected modifier key for the current OS.\n * This allows us to display correct shortcut key hints to users in the UI, and set up correct shortcut key bindings.\n *\n * @returns {string} either 'cmd' if on macOS, or 'ctrl' otherwise\n */\nexport const getOSKeyboardModifierKeyString = () =>\n currentOS() === 'macOS' ? 'cmd' : 'ctrl';\n\n/**\n * @returns {string} A string representing the locale as per the user's browser settings\n */\nexport const getCurrentLocale = () => navigator.language;\n"],"sourceRoot":""}