Created
June 16, 2026 18:16
-
-
Save whatnickcodes/ad493722222b177abb96b4b391379b9d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <style> | |
| #action-network-embed [data-action-network-src] { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| margin: -1px; | |
| overflow: hidden; | |
| clip: rect(0, 0, 0, 0); | |
| white-space: nowrap; | |
| border: 0; | |
| } | |
| #action-network-embed [data-action-network-target] { | |
| min-height: 180px; | |
| } | |
| #action-network-embed .action-network-status { | |
| display: none; | |
| border: 1px solid currentColor; | |
| padding: 1rem; | |
| color: var(--color-primary-900); | |
| background: color-mix(in oklab, var(--color-accent-300) 14%, white); | |
| } | |
| #action-network-embed .is-invalid .action-network-status { | |
| display: block; | |
| } | |
| </style> | |
| <div id="action-network-embed" class="wait bg-gray-100 px-[5%] py-[10%] lg:py-[6%]"> | |
| <div class="max-w-[680px] mx-auto"> | |
| <div field-tab="Copy" class="text-center"> | |
| <div field="Eyebrow" class="heading-6 !text-secondary-700 motion-preset-slide-up-xs">Take action</div> | |
| <h2 field="Heading" class="heading-3 mt-2 motion-preset-slide-up-sm motion-delay-200">Join the campaign</h2> | |
| <p field-textarea="Description" class="p mt-4 max-w-[58ch] mx-auto motion-preset-slide-up-sm motion-delay-300">Add your name and stay connected.</p> | |
| </div> | |
| <div field-tab="Action Network" class="contents"> | |
| <div | |
| class="mt-8 motion-preset-slide-up-sm motion-delay-400" | |
| data-action-network-embed | |
| data-action-network-style="standard" | |
| data-action-network-layout="standard"> | |
| <div field-textarea="Action Network URL" data-action-network-src> | |
| https://actionnetwork.org/forms/demo-the-action-network-toolset | |
| </div> | |
| <div class="action-network-status mb-4" data-action-network-status role="status"></div> | |
| <div data-action-network-target></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| (function () { | |
| var ACTION_TYPES = { | |
| form: 'form', | |
| forms: 'form', | |
| petition: 'petition', | |
| petitions: 'petition', | |
| event: 'event', | |
| events: 'event', | |
| letter: 'letter', | |
| letters: 'letter', | |
| letter_campaign: 'letter_campaign', | |
| letter_campaigns: 'letter_campaign', | |
| call_campaign: 'call_campaign', | |
| call_campaigns: 'call_campaign', | |
| fundraising: 'fundraising', | |
| fundraiser: 'fundraising', | |
| fundraisers: 'fundraising', | |
| fundraising_page: 'fundraising', | |
| fundraising_pages: 'fundraising', | |
| ticketed_event: 'ticketed_event', | |
| ticketed_events: 'ticketed_event', | |
| } | |
| var STYLE_URLS = { | |
| standard: 'https://actionnetwork.org/css/style-embed-v3.css', | |
| 'default': 'https://actionnetwork.org/css/style-embed-v3.css', | |
| 'layout-only': 'https://actionnetwork.org/css/style-embed-whitelabel.css', | |
| layout: 'https://actionnetwork.org/css/style-embed-whitelabel.css', | |
| none: '', | |
| } | |
| function clean(value) { | |
| return String(value || '').replace(/^\s+|\s+$/g, '') | |
| } | |
| function own(object, key) { | |
| return Object.prototype.hasOwnProperty.call(object, key) | |
| } | |
| function isActionNetworkHost(hostname) { | |
| hostname = clean(hostname).toLowerCase() | |
| return hostname === 'actionnetwork.org' || /(^|\.)actionnetwork\.org$/.test(hostname) | |
| } | |
| function stripTrailingSlash(value) { | |
| return String(value || '').replace(/\/+$/, '') | |
| } | |
| function decodeHtml(value) { | |
| var textarea = document.createElement('textarea') | |
| textarea.innerHTML = value | |
| return textarea.value | |
| } | |
| function urlFromMaybeRelative(value) { | |
| value = clean(value) | |
| if (!value) return null | |
| if (value.charAt(0) === '/') value = 'https://actionnetwork.org' + value | |
| if (/^actionnetwork\.org\//i.test(value)) value = 'https://' + value | |
| if (/^(forms|petitions|events|letter_campaigns|call_campaigns|fundraising|fundraisers|ticketed_events)\//i.test(value)) { | |
| value = 'https://actionnetwork.org/' + value | |
| } | |
| try { | |
| var anchor = document.createElement('a') | |
| anchor.href = value | |
| if (!isActionNetworkHost(anchor.hostname)) return null | |
| var pathname = anchor.pathname || '/' | |
| if (pathname.charAt(0) !== '/') pathname = '/' + pathname | |
| return { | |
| href: anchor.href, | |
| hostname: anchor.hostname, | |
| pathname: pathname, | |
| search: anchor.search || '', | |
| } | |
| } catch (error) { | |
| return null | |
| } | |
| } | |
| function extractSrcFromEmbed(value) { | |
| var decoded = decodeHtml(value) | |
| var scriptMatch = decoded.match(/<script\b[^>]*\bsrc\s*=\s*(['"])(.*?)\1/i) | |
| if (scriptMatch) return scriptMatch[2] | |
| var urlMatch = decoded.match(/https?:\/\/(?:[a-z0-9-]+\.)?actionnetwork\.org[^\s"'<>]+/i) | |
| if (urlMatch) return urlMatch[0] | |
| var pathMatch = decoded.match(/\/(?:forms|petitions|events|letter_campaigns|call_campaigns|fundraising|fundraisers|ticketed_events)\/[^\s"'<>]+/i) | |
| return pathMatch ? pathMatch[0] : decoded | |
| } | |
| function decodeQueryPart(value) { | |
| try { | |
| return decodeURIComponent(String(value || '').replace(/\+/g, ' ')) | |
| } catch (error) { | |
| return String(value || '') | |
| } | |
| } | |
| function encodeQueryPart(value) { | |
| return encodeURIComponent(String(value || '')) | |
| } | |
| function queryPairs(search) { | |
| search = String(search || '').replace(/^\?/, '') | |
| if (!search) return [] | |
| var pairs = [] | |
| var chunks = search.split('&') | |
| for (var i = 0; i < chunks.length; i++) { | |
| if (!chunks[i]) continue | |
| var eq = chunks[i].indexOf('=') | |
| var key = eq === -1 ? chunks[i] : chunks[i].slice(0, eq) | |
| var value = eq === -1 ? '' : chunks[i].slice(eq + 1) | |
| pairs.push([decodeQueryPart(key), decodeQueryPart(value)]) | |
| } | |
| return pairs | |
| } | |
| function getQueryParam(search, key) { | |
| var pairs = queryPairs(search) | |
| for (var i = 0; i < pairs.length; i++) { | |
| if (pairs[i][0] === key) return pairs[i][1] | |
| } | |
| return '' | |
| } | |
| function setQueryParam(pairs, key, value) { | |
| var found = false | |
| for (var i = 0; i < pairs.length; i++) { | |
| if (pairs[i][0] === key) { | |
| if (!found) { | |
| pairs[i][1] = value | |
| found = true | |
| } else { | |
| pairs.splice(i, 1) | |
| i-- | |
| } | |
| } | |
| } | |
| if (!found) pairs.push([key, value]) | |
| } | |
| function hasQueryParam(pairs, key) { | |
| for (var i = 0; i < pairs.length; i++) { | |
| if (pairs[i][0] === key) return true | |
| } | |
| return false | |
| } | |
| function serializeQuery(pairs) { | |
| var out = [] | |
| for (var i = 0; i < pairs.length; i++) { | |
| if (pairs[i][0] === 'url') continue | |
| out.push(encodeQueryPart(pairs[i][0]) + '=' + encodeQueryPart(pairs[i][1])) | |
| } | |
| return out.join('&') | |
| } | |
| function pathParts(pathname) { | |
| var raw = stripTrailingSlash(pathname).split('/') | |
| var out = [] | |
| for (var i = 0; i < raw.length; i++) { | |
| if (raw[i]) out.push(raw[i]) | |
| } | |
| return out | |
| } | |
| function widgetFromCleanUrl(url, layout) { | |
| var parts = pathParts(url.pathname) | |
| var actionType = ACTION_TYPES[parts[0]] | |
| var slug = parts[1] | |
| if (!actionType || !slug) return null | |
| var params = queryPairs(url.search) | |
| setQueryParam(params, 'format', 'js') | |
| if (!hasQueryParam(params, 'source')) setQueryParam(params, 'source', 'widget') | |
| if (layout === 'full' && !hasQueryParam(params, 'style')) setQueryParam(params, 'style', 'full') | |
| return { | |
| type: actionType, | |
| slug: slug, | |
| src: 'https://actionnetwork.org/widgets/v6/' + actionType + '/' + slug + '?' + serializeQuery(params), | |
| targetId: 'can-' + actionType + '-area-' + slug | |
| } | |
| } | |
| function widgetFromScriptUrl(url) { | |
| var parts = pathParts(url.pathname) | |
| var widgetsIndex = -1 | |
| for (var i = 0; i < parts.length; i++) { | |
| if (parts[i] === 'widgets') { | |
| widgetsIndex = i | |
| break | |
| } | |
| } | |
| if (widgetsIndex === -1) return null | |
| var maybeVersion = parts[widgetsIndex + 1] | |
| var typeIndex = /^v\d+$/i.test(maybeVersion || '') ? widgetsIndex + 2 : widgetsIndex + 1 | |
| var actionType = ACTION_TYPES[parts[typeIndex]] || parts[typeIndex] | |
| var slug = parts[typeIndex + 1] | |
| if (!actionType || !slug) return null | |
| var params = queryPairs(url.search) | |
| setQueryParam(params, 'format', 'js') | |
| if (!hasQueryParam(params, 'source')) setQueryParam(params, 'source', 'widget') | |
| return { | |
| type: actionType, | |
| slug: slug, | |
| src: 'https://actionnetwork.org/' + parts.join('/') + '?' + serializeQuery(params), | |
| targetId: 'can-' + actionType + '-area-' + slug | |
| } | |
| } | |
| function widgetFromOembedUrl(url, layout) { | |
| if (stripTrailingSlash(url.pathname) !== '/oembed') return null | |
| var embedded = getQueryParam(url.search, 'url') | |
| if (!embedded) return null | |
| var actionUrl = urlFromMaybeRelative(embedded) | |
| if (!actionUrl) return null | |
| actionUrl.search = url.search | |
| return widgetFromCleanUrl(actionUrl, layout) | |
| } | |
| function normalizeWidget(raw, layout) { | |
| var source = extractSrcFromEmbed(raw) | |
| var url = urlFromMaybeRelative(source) | |
| if (!url) return null | |
| return widgetFromOembedUrl(url, layout) | |
| || widgetFromScriptUrl(url) | |
| || widgetFromCleanUrl(url, layout) | |
| } | |
| function requestedStyle(wrap) { | |
| var value = clean(wrap.getAttribute('data-action-network-style')).toLowerCase() | |
| return own(STYLE_URLS, value) ? value : 'standard' | |
| } | |
| function requestedLayout(wrap) { | |
| var value = clean(wrap.getAttribute('data-action-network-layout')).toLowerCase() | |
| return value === 'full' ? 'full' : 'standard' | |
| } | |
| function ensureStylesheet(style) { | |
| var href = STYLE_URLS[style] | |
| if (!href) return | |
| if (document.getElementById('mf-action-network-css-' + style.replace(/[^a-z0-9_-]/gi, '-'))) return | |
| var link = document.createElement('link') | |
| link.rel = 'stylesheet' | |
| link.href = href | |
| link.id = 'mf-action-network-css-' + style.replace(/[^a-z0-9_-]/gi, '-') | |
| link.setAttribute('data-action-network-css', style) | |
| document.head.appendChild(link) | |
| } | |
| function clearChildren(element) { | |
| while (element.firstChild) element.removeChild(element.firstChild) | |
| } | |
| function setInvalid(wrap, invalid) { | |
| var className = (' ' + (wrap.className || '') + ' ').replace(/\s+is-invalid\s+/g, ' ') | |
| if (invalid) className += ' is-invalid ' | |
| wrap.className = className.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ') | |
| } | |
| function setStatus(wrap, message) { | |
| var status = wrap.querySelector('[data-action-network-status]') | |
| setInvalid(wrap, Boolean(message)) | |
| if (status) status.textContent = message || '' | |
| } | |
| function renderActionNetworkEmbed(wrap) { | |
| var sourceEl = wrap.querySelector('[data-action-network-src]') | |
| var targetEl = wrap.querySelector('[data-action-network-target]') | |
| if (!sourceEl || !targetEl) return | |
| var raw = clean(sourceEl.textContent) | |
| if (!raw) { | |
| clearChildren(targetEl) | |
| setStatus(wrap, '') | |
| return | |
| } | |
| var style = requestedStyle(wrap) | |
| var layout = requestedLayout(wrap) | |
| var widget = normalizeWidget(raw, layout) | |
| if (!widget) { | |
| clearChildren(targetEl) | |
| setStatus(wrap, 'Use an Action Network action URL or widget embed.') | |
| return | |
| } | |
| ensureStylesheet(style) | |
| setStatus(wrap, '') | |
| clearChildren(targetEl) | |
| var target = document.createElement('div') | |
| target.id = widget.targetId | |
| target.style.width = '100%' | |
| targetEl.appendChild(target) | |
| var script = document.createElement('script') | |
| script.src = widget.src | |
| script.async = true | |
| script.setAttribute('data-action-network-widget', widget.type + ':' + widget.slug) | |
| targetEl.appendChild(script) | |
| } | |
| function init(root) { | |
| var embeds = root.querySelectorAll('[data-action-network-embed]') | |
| for (var i = 0; i < embeds.length; i++) renderActionNetworkEmbed(embeds[i]) | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', function () { init(document) }) | |
| } else { | |
| init(document) | |
| } | |
| })() | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment