1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> 7 8 <!-- Add to home screen for Safari on iOS --> 9 <meta name="apple-mobile-web-app-capable" content="yes"> 10 <meta name="apple-mobile-web-app-status-bar-style" content="black"> 11 12 <html lang="en"> 13<meta name="twitter:card" content="summary_large_image"> 14<meta property="og:type" content="article"/> 15 16 17 18 19 20 21 <title>Login</title> 22 23 <link rel="shortcut icon" href="/neon/resource/chambermusicamerica/images/favicon.gif"/> 24 <!-- Common styles and scripts --> 25 <link href="https://fonts.googleapis.com/css?family=Lato:400,700|Open+Sans:400,700,900|Source+Sans+Pro:400,700,900|Montserrat:400,700,900|Roboto:100,100i,300,300i,400,400i,500,500i,700,700i,900,900i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese" rel="stylesheet"> 26 27 <link href="/nx/portal-static/component/bootstrap/css/bootstrap.min.css" rel="stylesheet"> 28 <link href="/nx/portal-static/component/fontawesome-pro/css/all.min.css" rel="stylesheet"> 29 <link href="/nx/portal-static/component/fontawesome-pro/css/sharp-solid.min.css" rel="stylesheet"> 30 <link href="/nx/portal-static/component/cropperjs/cropper.min.css" rel="stylesheet"> 31 32 <link href="/nx/portal-static/css/portal/portal.all.css" rel="stylesheet"> 33 34 35 <!-- Custom Web Page only. Before customCss.css so org td/tr rules still win. --> 36 37 38 39 40 41 42 43 44 45 46 47<style> 48 49 .neon-body { 50 position: relative; 51 } 52 .neonfront { 53 position: relative; 54 z-index: 2; 55 } 56 .neon-background { 57 background: var(--page-bg-color, #E1D7DD); 58 background-image: var(--page-bg-image, url("")); 59 background-position: center; /* Center the image */ 60 background-repeat: no-repeat; /* Do not repeat the image */ 61 background-size: cover; /* Resize the background image to cover the entire container */ 62 height: 100%; 63 width: 100%; 64 transform: var(--page-bg-mirror, ); 65 background-position: var(--page-bg-align, center left); 66 position: fixed; 67 z-index: 1; 68 } 69 .neonfront_element .form-check-input:checked { 70 background-color: var(--out-line-calibration-color, rgba(158, 14, 99, 1))!important; 71 } 72 .neonfront_content_wrap{ 73 background: ; 74 backdrop-filter: blur(3px); 75 } 76 body { 77 font-family: var(--page-font); 78 } 79 .neonfront_content_title, .neonfront_content_desc { 80 font-family: var(--page-font, Source Sans Pro,sans-serif) !important; 81 color: var(--page-font-color, #222222)!important; 82 word-break: break-word; 83 } 84 .neonfront_content_wrap.overlay-dark .neonfront_content_title, 85 .neonfront_content_wrap.overlay-dark .neonfront_content_desc { 86 color: #ffffff !important; 87 } 88 .neonfront_content_wrap.overlay-light .neonfront_content_title, 89 .neonfront_content_wrap.overlay-light .neonfront_content_desc { 90 color: #222222 !important; 91 } 92 .btn-outline-primary,.btn-outline-primary:hover { 93 color: var(--out-line-calibration-color, rgba(158, 14, 99, 1))!important; 94 background-color: transparent !important; 95 border-color: #D9DFE3; 96 box-shadow: none !important; 97 } 98 .btn-outline-secondary:hover,.btn-outline-secondary:active,.btn-outline-secondary:focus{ 99 background-color: #fff!important; 100 color: var(--out-line-calibration-color, rgba(158, 14, 99, 1))!important; 101 border-color: #D9DFE3; 102 box-shadow: none !important; 103 } 104 105 .neonfront-btn-link { 106 color: var(--out-line-calibration-color, rgba(158, 14, 99, 1))!important; 107 } 108 .neonfront_stepper.on,.neonfront_stepper_num { 109 background: var(--theme-color, rgba(158, 14, 99, 1))!important; 110 } 111 112 .neonfront_payment_tab .active { 113 border-bottom: 4px solid var(--out-line-calibration-color, rgba(158, 14, 99, 1)) !important; 114 color: var(--out-line-calibration-color, rgba(158, 14, 99, 1)) !important; 115 } 116 117 .neonfront-btn-primary, .btn-primary { 118 background-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 119 color: var(--primary-btn-text-color, #ffffff) !important; 120 border-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 121 box-shadow: none !important; 122 } 123 .secondary-exit-btn { 124 color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 125 background-color: #FFF !important; 126 border: 1px solid var(--theme-color, rgba(158, 14, 99, 1)) !important; 127 box-shadow: none !important; 128 } 129 130 .neonfront-btn-paypal { 131 background-color: #f7c457 !important; 132 } 133 134 .btn-primary, .form-check-input:checked { 135 border-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 136 } 137 138 .neonfront-btn-outline-primary { 139 color: var(--out-line-calibration-color, rgba(158, 14, 99, 1))!important; 140 } 141 142 .btn-check:checked + .neonfront-btn-outline-primary, .donationFrequencyChecked, .btn-check:active + .neonfront-btn-outline-primary, .neonfront-btn-outline-primary.active, .neonfront-btn-outline-primary.dropdown-toggle.show { 143 background-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 144 border-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 145 color: var(--primary-btn-text-color, #ffffff) !important; 146 z-index: 0 !important; 147 } 148 149 .donation-frequency-default-select-icon-bg { 150 background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' %3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); 151 } 152 153 .neonfront-check-input-level:checked + .neonfront-btn-level, .neonfront-check-input-level:active + .neonfront-btn-level, .neonfront-btn-level:active, .neonfront-btn-level.active, .neonfront-btn-level.dropdown-toggle.show { 154 border-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 155 } 156 157 .container-fluid.neonfront_header { 158 color: var(--header-text-color, #222222) !important; 159 background-color: var(--header-bg-color, #FFFFFF)!important; 160 } 161 .container-fluid.neonfront_header .navbar-toggler { 162 color: var(--header-text-color, #222222) !important; 163 z-index: 100; 164 } 165 .container-fluid.neonfront_footer { 166 color: var(--footer-text-color, #ffffff)!important; 167 background-color: var(--footer-bg-color, rgba(37, 0, 57, 1))!important; 168 padding-left: 0px; 169 padding-right: 0px; 170 } 171 .neonfront_footer_lv_info { 172 color: var(--footer-text-color, #ffffff)!important; 173 font-family: var(--page-font, Lato); 174 font-style: normal; 175 font-weight: 400; 176 font-size: 14px; 177 padding-top: 21px; 178 padding-bottom: 3px; 179 word-break: break-word; 180 min-height: 30px; 181 } 182 .neonfront_footer_lv_info a{ 183 color: var(--footer-text-color, #ffffff); 184 text-decoration: underline!important; 185 } 186 .neonfront_header .neonfront_link { 187 color: var(--header-text-color, #222222)!important; 188 } 189 .neonfront-profile-dropdown .fa-caret-down { 190 color: #3C4144!important; 191 } 192 .neonfront-profile-dropdown .name { 193 background-color: #3C4144!important; 194 color: #ffffff!important; 195 } 196 .neonfront_header .neonfront_link.login_button { 197 border-color: var(--header-text-color, #222222)!important; 198 width: 78px; 199 height: 32px; 200 padding: 0px 0px 2px 0px !important; 201 margin-left: 15px; 202 } 203 .neonfront_footer_lv_info .neonfront_link { 204 color: var(--footer-text-color, #ffffff)!important; 205 } 206 207 .neonfront-switch input:checked{ 208 background-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 209 } 210 211 .popal-opportunities-tile .popal-opportunities-tile-col .pot-neon-round-img { 212 background-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 213 color: var(--primary-btn-text-color, #ffffff) !important; 214 } 215 .portal-volunteer-info-main .opportunity-app-col1 .module-icon-round { 216 background-color: var(--theme-color, rgba(158, 14, 99, 1)) !important; 217 color: var(--primary-btn-text-color, #ffffff) !important; 218 } 219</style> 220<!-- Monthly Giving Suggestion (MGS) Styles --> 221 222
223<script type="text/javascript"> 224 function setCalibrationColor(color) { 225 if (color) { 226 color = color.replace(/['"]/g, '') 227 let darkText = '#222222' 228 let lightText = '#ffffff' 229 color = this.contrastRatioColor(color, darkText) > this.contrastRatioColor(color, lightText) ? darkText : color 230 document.documentElement.style.setProperty("--out-line-calibration-color", color); 231 } 232 } 233 function contrastRatioColor(color1, color2) { 234 let color1luminanceColor = this.luminanceColor(color1) 235 let color2luminanceColor = this.luminanceColor(color2) 236 return color1luminanceColor > color2luminanceColor 237 ? ((color1luminanceColor + 0.05) / (color2luminanceColor + 0.05)) 238 : ((color2luminanceColor + 0.05) / (color1luminanceColor + 0.05)) 239 } 240 function luminanceColor(color) { 241 let rgbColor = /rgba?/.test(color) ? this.rgbaColorToRgbMap(color) : this.hexColorToRgb(color) 242 let rgb = [rgbColor.r, rgbColor.g, rgbColor.b].map(function (x) { x /= 255 243 return x <= 0.03928 244 ? x / 12.92 245 : Math.pow((x + 0.055) / 1.055, 2.4) 246 }) 247 return rgb[0] * 0.2126 + rgb[1] * 0.7152 + rgb[2] * 0.0722 248 }; 249 function rgbaColorToRgbMap(rgba) { 250 let result = rgba.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d(?:\.\d?))\))?/); 251 return result ? {r: parseInt(result[1]), g: parseInt(result[2]), b: parseInt(result[3])} : null 252 } 253 function hexColorToRgb(hex) { 254 let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) 255 return result ? { 256 r: parseInt(result[1], 16), 257 g: parseInt(result[2], 16), 258 b: parseInt(result[3], 16) 259 } : null 260 } 261</script>
vendor: 1 bytes, line 261
261
262<script> 263 /* ================================================================ 264 * Portal Theme JS (included via th:replace from theme/theme.html) 265 * Provides: 266 * SOCIAL_ICON_CONFIG / getSocialIconURL(name, style) 267 * applyThemeCSSVars(theme) 268 * postMessage listener for live-preview iframe 269 * ================================================================ */ 270 271 // ââ Social Icons ââââââââââââââââââââââââââââââââââââââââââââââââââ 272 const SOCIAL_ICON_BASE = '/nx/portal-static/img/social-icon'; 273 274 const SOCIAL_ICON_CONFIG = { 275 Website: {color: 'website-color.svg', white: 'website-white.svg', black: 'website-black.svg'}, 276 Email: {color: 'email-color.svg', white: 'email-white.svg', black: 'email-black.svg'}, 277 Facebook: {color: 'facebook-color.png', white: 'facebook-white.png', black: 'facebook-color.png'}, // no black â brand rule 278 Flickr: {color: 'flickr-color.png', white: 'flickr-white.png', black: 'flickr-black.png'}, 279 Instagram: {color: 'instagram-color.png', white: 'instagram-white.png', black: 'instagram-black.png'}, 280 LinkedIn: {color: 'linkedin-color.png', white: 'linkedin-white.png', black: 'linkedin-black.png'}, 281 Pinterest: {color: 'pinterest-color.png', white: 'pinterest-white.png', black: 'pinterest-black.png'}, 282 Snapchat: {color: 'snapchat-color.png', white: 'snapchat-white.png', black: 'snapchat-black.png'}, 283 SoundCloud: {color: 'soundcloud-white.png', white: 'soundcloud-white.png', black: 'soundcloud-black.png'}, // no color â reuses white 284 Spotify: {color: 'spotify-color.png', white: 'spotify-white.png', black: 'spotify-black.png'}, 285 Vimeo: {color: 'vimeo-color.png', white: 'vimeo-white.png', black: 'vimeo-black.png'}, 286 X: {color: 'x-white.png', white: 'x-white.png', black: 'x-black.png'}, // no color â reuses white 287 YouTube: {color: 'youtube-color.png', white: 'youtube-white.png', black: 'youtube-black.png'} 288 }; 289 290 function getSocialIconURL(name, style) { 291 // A backend bug (BrandDataManager/PersistSystemSettingAction) previously saved 'Twitter' 292 // instead of 'X' for this icon; normalize so those existing records still render. 293 const key = name === 'Twitter' ? 'X' : name; 294 const cfg = SOCIAL_ICON_CONFIG[key]; 295 if (!cfg) return '' 296 const styleMap = {C: 'color', L: 'white', D: 'black'}; 297 const file = cfg[styleMap[style] || 'color'] || ''; 298 return file ? SOCIAL_ICON_BASE + '/' + file : '' 299 } 300 301 // ââ Hosted Brand Fonts âââââââââââââââââââââââââââââââââââââââââââââ 302 303 const SYSTEM_FONT_NAMES = ['Arial', 'Comic Sans MS', 'Courier New', 'Georgia', 'Tahoma', 'Lucida Sans Unicode', 'Times New Roman', 'Trebuchet MS', 'Verdana']; 304 305 function getBrandFontName(fontFamilyValue) { 306 if (!fontFamilyValue || typeof fontFamilyValue !== 'string') return '' 307 return fontFamilyValue.split(',')[0].trim().replace(/^['"]|['"]$/g, '') 308 } 309 310 function loadHostedBrandFontFromFamily(fontFamilyValue) { 311 const fontName = getBrandFontName(fontFamilyValue); 312 if (!fontName || SYSTEM_FONT_NAMES.indexOf(fontName) > -1) return 313 314 const linkId = 'brand-font-' + fontName.toLowerCase().replace(/[^a-z0-9]+/g, '-'); 315 if (document.getElementById(linkId)) return 316 317 const link = document.createElement('link'); 318 link.id = linkId; 319 link.rel = 'stylesheet'; 320 link.href = 'https://fonts.googleapis.com/css2?family=' + encodeURIComponent(fontName).replace(/%20/g, '+') + '&display=swap'; 321 document.head.appendChild(link); 322 } 323 324 // ââ CSS Variables âââââââââââââââââââââââââââââââââââââââââââââââââ 325 326 /** 327 * Parse a color string to {r,g,b,a}. 328 * Supports: #rgb / #rrggbb / #rrggbbaa / rgb(...) / rgba(...) 329 * Returns null if the input is not a recognized format. 330 */ 331 function hexToRgba(color) { 332 if (!color || typeof color !== 'string') return null 333 var c = color.trim() 334 // rgb(r, g, b) or rgba(r, g, b, a) 335 var rgbMatch = c.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/) 336 if (rgbMatch) { 337 return { 338 r: parseInt(rgbMatch[1]), 339 g: parseInt(rgbMatch[2]), 340 b: parseInt(rgbMatch[3]), 341 a: rgbMatch[4] !== undefined ? parseFloat(rgbMatch[4]) : 1 342 } 343 } 344 // #hex 345 if (c[0] !== '#') return null 346 var h = c.substring(1) 347 if (h.length === 3) { h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2] } 348 if (h.length !== 6 && h.length !== 8) return null 349 return { 350 r: parseInt(h.substring(0, 2), 16), 351 g: parseInt(h.substring(2, 4), 16), 352 b: parseInt(h.substring(4, 6), 16), 353 a: h.length === 8 ? (parseInt(h.substring(6, 8), 16) / 25
3535) : 1 354 } 355 } 356 357 /** 358 * Compute accessible font color (#222222 or #ffffff) based on WCAG contrast ratio. 359 * Reuses the existing hexToRgba() helper defined above. 360 */ 361 function computeInverseColor(bgColor) { 362 if (!bgColor) return '#222222' 363 function luminance(color) { 364 const rgba = hexToRgba(color); 365 if (!rgba) return 0 366 return [rgba.r, rgba.g, rgba.b].map(function(x) { 367 x /= 255 368 return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4) 369 }).reduce(function(sum, v, i) { return sum + v * [0.2126, 0.7152, 0.0722][i] }, 0) 370 } 371 function contrastRatio(l1, l2) { return l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05) } 372 373 const lBg = luminance(bgColor); 374 return contrastRatio(lBg, luminance('#222222')) > contrastRatio(lBg, luminance('#ffffff')) ? '#222222' : '#ffffff' 375 } 376 377 /** 378 * Write theme config as :root CSS variables so the page can update 379 * in real-time (live preview via postMessage, or on initial load). 380 * Only sets a var when the corresponding value is non-empty. 381 */ 382 function applyThemeCSSVars(theme) { 383 if (!theme) return 384 const styles = theme.styles || {}; 385 const root = document.documentElement; 386 387 loadHostedBrandFontFromFamily(styles.pageFont) 388 389 // Helper: set only when value is truthy; clear the var when value is empty 390 function set(name, value) { 391 if (value !== null && value !== undefined && value !== '') { 392 root.style.setProperty(name, value) 393 } else if (value === '' || value === null) { 394 root.style.removeProperty(name) 395 } 396 } 397
398 function setColorOrTransparent(name, value) { 399 root.style.setProperty(name, (value !== null && value !== undefined && value !== '') ? value : 'transparent') 400 } 401 402 function setColorOrBlack(name, value) { 403 root.style.setProperty(name, (value !== null && value !== undefined && value !== '') ? value : '#000000') 404 } 405 406 function setOrKeepPrevious(name, value) { 407 if (value !== null && value !== undefined && value !== '') { 408 root.style.setProperty(name, value) 409 } 410 } 411 412 // ââ Core theme vars (used by theme.html CSS) ââ 413 setOrKeepPrevious('--theme-color', styles.themeColor) 414 setColorOrTransparent('--page-bg-color', styles.pageBgColor) 415 set('--page-font', styles.pageFont) 416 set('--page-font-color', computeInverseColor(styles.pageBgColor)) 417 setOrKeepPrevious('--primary-btn-text-color', styles.themeColor ? computeInverseColor(styles.themeColor) : null)
418 setColorOrTransparent('--header-bg-color', styles.headerBgColor) 419 setColorOrBlack('--header-text-color', styles.headerTextColor) 420 setColorOrTransparent('--footer-bg-color', styles.footerBgColor) 421 setColorOrBlack('--footer-text-color', styles.footerTextColor) 422 423 // bg-image: wrap in url() when non-empty, clear when empty 424 if (styles.pageBgImage && styles.pageBgImage !== '') { 425 root.style.setProperty('--page-bg-image', 'url("' + styles.pageBgImage + '")') 426 } else { 427 root.style.setProperty('--page-bg-image', '') 428 } 429 430 // bg-position: default 50% when absent 431 root.style.setProperty('--page-bg-align', 432 (styles.pageBgAlign && styles.pageBgAlign !== '') ? styles.pageBgAlign : '50%') 433 434 // bg-mirror: '1' â rotateY(180deg), else empty 435 root.style.setProperty('--page-bg-mirror', 436 styles.pageBgMirror === '1' ? 'rotateY(180deg)' : '') 437 438 // ââ Campaign landing page vars (portal-landing-page.css, portal-constituent.css) ââ 439 set('--landing-page-font-family', styles.pageFont) 440 set('--landing-page-font-color', computeInverseColor(styles.pageBgColor)) 441 setOrKeepPrevious('--landing-page-theme-color', styles.themeColor) 442 setOrKeepPrevious('--primary-theme-color', styles.themeColor) 443 setOrKeepPrevious('--landing-page-btn-text-color', styles.themeColor ? computeInverseColor(styles.themeColor) : null) 444 // defaultBackgroundColor is resolved from themeColor (same value), used when no hero image 445 setOrKeepPrevious('--landing-page-hero-bg-color', styles.themeColor) 446 447 // ââ themeColor â RGBA decomposition ââ 448 // Updates --campaign-progress-r/g/b/a (campaign-progress.css) 449 // and --goal-meter-widget-r/g/b/a and computes opacity variants for landing page 450 if (styles.themeColor) { 451 const rgba = hexToRgba(styles.themeColor); 452 if (rgba) { 453 root.style.setProperty('--campaign-progress-r', rgba.r) 454 root.style.setProperty('--campaign-progress-g', rgba.g) 455 root.style.setProperty('--campaign-progress-b', rgba.b) 456 root.style.setProperty('--campaign-progress-a', rgba.a) 457 root.style.setProperty('--goal-meter-widget-r', rgba.r) 458 root.style.setProperty('--goal-meter-widget-g', rgba.g) 459 root.style.setProperty('--goal-meter-widget-b', rgba.b) 460 root.style.setProperty('--goal-meter-widget-a', rgba.a) 461 root.style.setProperty('--landing-page-theme-color-opacity', 462 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',0.15)') 463 root.style.setProperty('--landing-page-theme-color-opacity-over', 464 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',0.7)') 465 } 466 } 467 468 // keep calibration in sync 469 if (styles.themeColor && typeof setCalibrationColor === 'function') { 470 setCalibrationColor(styles.themeColor) 471 } 472 473 let extraConfig = theme.extraConfig ? theme.extraConfig : {} 474 if (extraConfig && extraConfig.correctDashboard) { 475 if (extraConfig.useWhiteHeader) { 476 root.style.setProperty('--dashboard-header-color', '#fff') 477 root.style.setProperty('--dashboard-header-text-color', '#3C4144') 478 root.style.setProperty('--dashboard-header-hover-link-color', '#E2F2FE') 479 } else {
480 setColorOrTransparent('--dashboard-header-color', styles.headerBgColor) 481 setColorOrBlack('--dashboard-header-text-color', styles.headerTextColor) 482 setColorOrTransparent('--dashboard-header-hover-link-color', styles.headerBgColor) 483 } 484 } else { 485 // Clear dashboard-specific vars when not on dashboard to avoid unintended overrides 486 root.style.removeProperty('--dashboard-header-color') 487 root.style.removeProperty('--dashboard-header-text-color') 488 root.style.removeProperty('--dashboard-header-hover-link-color') 489 } 490 491 // ââ Fullscreen preview: hide/show dashboard-specific elements â 492 let fullscreenStyle = document.getElementById('_neonFullscreenStyle') 493 if (!fullscreenStyle) { 494 fullscreenStyle = document.createElement('style') 495 fullscreenStyle.id = '_neonFullscreenStyle' 496 document.head.appendChild(fullscreenStyle) 497 } 498 if (extraConfig && extraConfig.fullscreen === false) { 499 fullscreenStyle.textContent = '.neonfront-portal-left-nav { visibility: hidden !important; } .neonfront-portal-nav-bar { display: none !important; } .dashboard_welcome .sidebar-title { display: none !important; } .dashboard_welcome .welcome-text { margin-left: 16px; }' 500 } else { 501 fullscreenStyle.textContent = '' 502 } 503 } 504 505 // ââ Footer column text and naviLinks processing âââââââââââââââââââ 506 // Replace tokens in footer col texts and naviLink URLs via a single backend call. 507 // If no relevant data, calls onDone immediately without an API request. 508 function processFooterColTexts(theme, onDone) { 509 const hasFooter = theme.footerCol1Text || theme.footerCol2Text || theme.footerCol3Text; 510 const hasNaviToken = theme.naviLinks && theme.naviLinks.some(function (l) { 511 return l.url && l.url.indexOf('Organization URL') !== -1; 512 }); 513 if (!hasFooter && !hasNaviToken) { 514 onDone(theme); 515 return; 516 } 517 axios.post('/nx/portal/theme/processColTexts', { 518 footerCol1Text: theme.footerCol1Text, 519 footerCol2Text: theme.footerCol2Text, 520 footerCol3Text: theme.footerCol3Text, 521 naviLinks: theme.naviLinks, 522 }).then(function (res) { 523 var processed = theme; 524 if (res.data && res.data.success && res.data.data) { 525 processed = Object.assign({}, theme, res.data.data); 526 } 527 onDone(processed); 528 }).catch(function (e) { 529 onDone(theme); 530 }); 531 } 532 533 // ââ Footer request token: UUID-based guard against stale async callbacks ââ 534 // Each DOMContentLoaded or postMessage generates a new UUID token. 535 // Any async callback whose token no longer matches the current one is discarded. 536 window._neonFooterToken = null; 537 window._neonFooterDebounceTimer = null; 538 window._neonPrevTheme = null; // cache of last applied patchData (excludes footer cols) 539 window._neonPrevTokenSrc = null; // cache of raw source for token-processed fields (naviLinks + footer cols) 540 541 // Deep-equal comparison: JSON for objects/arrays, strict for primitives. 542 function _themeValEqual(a, b) { 543 if (a === b) return true; 544 if (a == null || b == null) return a === b; 545 if (typeof a === 'object') return JSON.stringify(a) === JSON.stringify(b); 546 return false; 547 } 548 549 // Recursively patch only changed properties on a Vue reactive target. 550 // Plain objects are patched property-by-property; arrays/primitives are assigned directly. 551 function _patchReactive(target, source, prev) { 552 Object.keys(source).forEach(function(k) { 553 const nv = source[k], pv = prev ? prev[k] : undefined; 554 if (prev && _themeValEqual(pv, nv)) return; 555 const tIsObj = target[k] != null && typeof target[k] === 'object' && !Array.isArray(target[k]); 556 const nIsObj = nv != null && typeof nv === 'object' && !Array.isArray(nv); 557 if (tIsObj && nIsObj) _patchReactive(target[k], nv, pv || {}); 558 else target[k] = nv; 559 }); 560 } 561 562 // ââ Initial page load: wait for DOM, then process footer ââââââââââ 563 document.addEventListener('DOMContentLoaded', function () { 564 565 // ââ CLP embed: set before Vue mounts so clpEmbedEnv is reactive âââ 566 if (new URLSearchParams(window.location.search).get('clpEmbedEnv') === '1') { 567 sessionStorage.setItem('clpEmbedEnv', '1'); 568 } 569 if (window.top !== window.self && sessionStorage.getItem('clpEmbedEnv') === '1') { 570 const _clpStyle = document.createElement('style'); 571 _clpStyle.id = '_clpEmbedStyle'; 572 _clpStyle.textContent = '#header-content, #footer-content { display: none !important; }'; 573 document.head.appendChild(_clpStyle); 574 } 575 576 var theme = window._neonThemeData; 577 if (!theme) return; 578 loadHostedBrandFontFromFamily(theme.styles && theme.styles.pageFont); 579 var myToken = crypto.randomUUID(); 580 window._neonFooterToken = myToken; 581 // Hide footer cols while processing to avoid showing raw tokens 582 if (window.__neonApp) { 583 window.__neonApp.theme = Object.assign({}, window.__neonApp.theme, { 584 footerCol1Text: '', 585 footerCol2Text: '', 586 footerCol3Text: '', 587 }); 588 } 589 processFooterColTexts(theme, function (processed) { 590 if (window._neonFooterToken !== myToken) return; 591 if (window.__neonApp) { 592 window.__neonApp.theme = Object.assign({}, window.__neonApp.theme, { 593 footerCol1Text: processed.footerCol1Text, 594 footerCol2Text: processed.footerCol2Text, 595 footerCol3Text: processed.footerCol3Text, 596 naviLinks: processed.naviLinks, 597 }); 598 } 599 }); 600 }); 601 602 // ââ CLP embed: listen for parent postMessage (handles already-logged-in scenario) ââ 603 window.addEventListener('message', function (event) { 604 if (!event.data || event.data.sharingType !== 'clpEmbed') return; 605 if (window.top === window.self) { 606 return; 607 } 608 sessionStorage.setItem('clpEmbedEnv', '1'); 609 if (event.data.embedIframeId) sessionStorage.setItem('clpEmbedIframeId', event.data.embedIframeId); 610 if (event.data.domainUrl) sessionStorage.setItem('clpEmbedDomainUrl', event.data.domainUrl); 611 if (!document.getElementById('_clpEmbedStyle')) { 612 const _clpStyle = document.createElement('style'); 613 _clpStyle.id = '_clpEmbedStyle'; 614 _clpStyle.textContent = '#header-content, #footer-content { display: none !important; }'; 615 document.head.appendChild(_clpStyle); 616 } 617 }); 618 619 // ââ postMessage listener (live preview) âââââââââââââââââââââââââââ 620 window.addEventListener('message', function (event) { 621 if (!event.data || event.data.type !== 'NEON_THEME_PREVIEW') return 622 let newTheme = event.data.template; 623 if (!newTheme) return 624 625 console.log('NEON_THEME_PREVIEW received', newTheme); 626 627 const myToken = crypto.randomUUID(); 628 window._neonFooterToken = myToken; 629 630 const ALIGN_MAP = {LEFT: 'L', CENTER: 'C', RIGHT: 'R', L: 'L', C: 'C', R: 'R'}; 631 const COLOR_MAP = {COLOR: 'C', WHITE: 'L', BLACK: 'D', C: 'C', W: 'L', B: 'D', L: 'L', D: 'D'}; 632 633 function enumVal(v, map, fb) { if (!v) return fb; if (typeof v === 'object') v = v.value || fb; return map[v] || fb } 634 635 newTheme = Object.assign({}, newTheme, { 636 extraConfig: event.data.extraConfig || {}, 637 socialLinkIconAlign: enumVal(newTheme.socialLinkIconAlign, ALIGN_MAP, 'L'), 638 socialLinkIconStyle: enumVal(newTheme.socialLinkIconStyle, COLOR_MAP, 'L'), 639 }) 640 641 // ââ Step 1: immediately patch only changed non-footer properties ââ 642 // Footer cols are excluded: hidden while API processes to avoid showing raw tokens. 643 // naviLinks included: raw URL changes are shown immediately (same as before). 644 const patchData = Object.assign({}, newTheme); 645 delete patchData.footerCol1Text; 646 delete patchData.footerCol2Text; 647 delete patchData.footerCol3Text; 648 649 const prev = window._neonPrevTheme; 650 const changedKeys = Object.keys(patchData).filter(function (k) { 651 return !prev || !_themeValEqual(prev[k], patchData[k]); 652 }); 653 if (changedKeys.length > 0) { 654 const target = window.__neonApp ? window.__neonApp.theme : window._neonThemeData; 655 if (target) _patchReactive(target, patchData, prev); 656 if (changedKeys.indexOf('styles') !== -1 || changedKeys.indexOf('extraConfig') !== -1) { 657 applyThemeCSSVars(patchData); 658 } 659 window._neonPrevTheme = JSON.parse(JSON.stringify(patchData)); 660 } 661 662 // ââ Step 2: debounce token API only when naviLinks or footer cols source changed ââ 663 const tokenSrc = { 664 col1: newTheme.footerCol1Text, 665 col2: newTheme.footerCol2Text, 666 col3: newTheme.footerCol3Text, 667 nav: JSON.stringify(newTheme.naviLinks), 668 }; 669 const ps = window._neonPrevTokenSrc; 670 if (ps && ps.col1 === tokenSrc.col1 && ps.col2 === tokenSrc.col2 && ps.col3 === tokenSrc.col3 && ps.nav === tokenSrc.nav) return; 671 672 clearTimeout(window._neonFooterDebounceTimer) 673 window._neonFooterDebounceTimer = setTimeout(function () { 674 const capturedToken = myToken; 675 processFooterColTexts(newTheme, function (processed) { 676 if (window._neonFooterToken !== capturedToken) return; 677 if (window.__neonApp) { 678 window.__neonApp.theme['naviLinks'] = processed.naviLinks; 679 window.__neonApp.theme['footerCol1Text'] = processed.footerCol1Text; 680 window.__neonApp.theme['footerCol2Text'] = processed.footerCol2Text; 681 window.__neonApp.theme['footerCol3Text'] = processed.footerCol3Text; 682 } 683 window._neonPrevTokenSrc = tokenSrc; 684 window.parent.postMessage({ type: 'NEON_THEME_READY' }, '*') 685 }) 686 }, 300) 687 }) 688</script>
vendor: 1 bytes, line 688
688
689<script> 690 window._neonThemeData = { 691 id: 9, 692 logo: "https:\/\/chambermusicamerica.app.neoncrm.com\/np\/clients\/chambermusicamerica\/logo.gif", 693 logoAlt: null, 694 logoWidth: 100, 695 logoUrl: null, 696 footerColumns: 3, 697 footerCol1Text: "<p><a href=\"http:\/\/www.chambermusicamerica.org\" target=\"_blank\" rel=\"noopener\">CMA Main Website Home<\/a><\/p>", 698 footerCol2Text: "<p>P.O. Box 22248<br>Brooklyn, NY 11202<\/p>", 699 footerCol3Text: "<p><a href=\"https:\/\/chambermusicamerica.org\/contact-us\/\" target=\"_self\">Contact Us<\/a><\/p>\n<p><a href=\"https:\/\/chambermusicamerica.org\/privacy-policy\/\" target=\"_self\">Privacy Policy<\/a><\/p>\n<p><a href=\"https:\/\/chambermusicamerica.org\/our-impact\/\" target=\"_blank\" rel=\"noopener\">CMA's Impact<\/a><\/p>", 700 displaySocialLink: true, 701 socialLinkIconAlign: "C", 702 socialLinkIconStyle: "L", 703 styles: {"headerBgColor":"#FFFFFF","headerTextColor":"#222222","pageFont":"Source Sans Pro,sans-serif","pageBgColor":"#E1D7DD","pageBgMirror":"0","pageBgImage":"https:\/\/chambermusicamerica.app.neoncrm.com\/neon\/resource\/chambermusicamerica\/images\/CMA25-Sat-TrishBadger-075.jpg","themeJSSnippets":"","pageBgImageAlt":"CMA25-Sat-TrishBadger-075.jpg","themeColor":"rgba(158, 14, 99, 1)","footerBgColor":"rgba(37, 0, 57, 1)","pageBgAlign":"center left","pageFontColor":"#002D41","footerTextColor":"#ffffff","primaryBtnTextColor":"#ffffff","actBtnTextColor":"rgba(158, 14, 99, 1)"}, 704 socialLinks: [{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":191,"templateId":9,"icon":"Website","url":"https:\/\/chambermusicamerica.org"},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":192,"templateId":9,"icon":"Facebook","url":"https:\/\/facebook.com\/chambermusicamerica"},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":193,"templateId":9,"icon":"Instagram","url":"https:\/\/instagram.com\/chambermusicamerica"},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":194,"templateId":9,"icon":"YouTube","url":"https:\/\/youtube.com\/chambermusicamerica"},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":195,"templateId":9,"icon":"LinkedIn","url":"https:\/\/linkedin.com\/company\/chamber-music-america"}], 705 naviLinks: [{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":124,"templateId":9,"url":"https:\/\/members.chambermusicamerica.org\/nx\/portal\/neonevents\/events?path=%2Fportal%2Fevents","name":"CMA Events","openInNewTab":1},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":125,"templateId":9,"url":"https:\/\/chambermusicamerica.org\/become-a-member\/","name":"Join Membership","openInNewTab":1},{"createBy":"Jenny Ouellette","createTime":"2026-01-21T14:31:12.000-06:00","lastModifyBy":"Jenny Ouellette","lastModifyTime":"2026-01-21T14:31:12.000-06:00","id":126,"templateId":9,"url":"https:\/\/chambermusicamerica.org\/news\/","name":"CMA News \u0026 Insights","openInNewTab":1}], 706 _homePageURL: "https:\/\/chambermusicamerica.org", 707 _previewMode: false, 708 } 709 applyThemeCSSVars(window._neonThemeData) 710</script>
710 711 712 713 </head> 714<body> 715<div class="neon-body" id="app" v-cloak=""> 716 <div class="neon-background"></div> 717 <div class="neonfront"> 718 719<!DOCTYPE html> 720<html> 721<body> 722 <nav class="navbar navbar-expand-lg pt-0" style="padding-bottom: 0!important;" id="header-content"> 723 <div style="position: relative; width: 100%"> 724 <div class="container-fluid neonfront_header"> 725 <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> 726 <i class="fas fa-bars"></i> 727 </button> 728 <div class="navbar-brand"> 729 <div class="neonfront_logo"> 730 <!-- Case 1: logoUrl set -> link to logoUrl, open in new tab --> 731 <a v-if="theme.logoUrl" 732 :href="theme.logoUrl.startsWith('http://') || theme.logoUrl.startsWith('https://') || theme.logoUrl.startsWith('//') ? theme.logoUrl : 'https://' + theme.logoUrl" 733 :style="theme._previewMode ? {'pointer-events': 'none'} : {}" 734 target="_blank"> 735 <img v-if="theme.logo && theme.logoWidth !== 0" :src="theme.logo" :width="theme.logoWidth || undefined" :alt="theme.logoAlt" onerror="this.style.display='none';"/> 736 <span v-else-if="!theme.logo">{{theme.logoAlt}}</span> 737 </a> 738 <!-- Case 2: no logoUrl but homePageURL -> original behavior --> 739 <a v-else-if="theme._homePageURL" 740 :href="theme._homePageURL.startsWith('http://') || theme._homePageURL.startsWith('https://') || theme._homePageURL.startsWith('//') ? theme._homePageURL : 'https://' + theme._homePageURL" 741 :style="theme._previewMode ? {'pointer-events': 'none'} : {}" 742 target="_blank"> 743 <img v-if="theme.logo && theme.logoWidth !== 0" :src="theme.logo" :width="theme.logoWidth || undefined" :alt="theme.logoAlt" onerror="this.style.display='none';"/> 744 <span v-else-if="!theme.logo">{{theme.logoAlt}}</span> 745 </a> 746 <!-- Case 3: no link --> 747 <template v-else> 748 <img v-if="theme.logo && theme.logoWidth !== 0" :src="theme.logo" :width="theme.logoWidth || undefined" :alt="theme.logoAlt" onerror="this.style.display='none';"/> 749 <span v-else-if="!theme.logo">{{theme.logoAlt}}</span> 750 </template> 751 </div> 752 </div> 753 <div class="collapse navbar-collapse" id="navbarSupportedContent"> 754 <ul class="neonfront_links navbar-nav mb-2 mb-lg-0"> 755 <template v-for="link in theme.naviLinks" :key="link.id"> 756 <li v-if="link.url && link.name" class="nav-item"> 757 <a class="neonfront_link" :href="!link.url ? '#' : link.url.startsWith('http://') || link.url.startsWith('https://') ? (link.url === 'http://' || link.url === 'https://' ? '#' : link.url) : 'https://' + link.url" 758 :style="theme._previewMode ? {'pointer-events': 'none'} : {}" 759 :target="link.openInNewTab==1 ? '_blank' : '_self'">{{link.name}}</a> 760 </li> 761 </template> 762 763 764 </ul> 765 </div> 766 </div> 767 </div> 768 </nav> 769</body> 770</html> 771 772 773 <div class="neonfront_cover container-fluid"> 774 775 <div class="row flex-grow-1" id="content"> 776 <div class="col"> 777 <div class="d-flex neonfront-portal-content"> 778 <!-- Left Menu --> 779 780 781 <!-- Right Content --> 782 <div class="flex-grow-1" id="right-content"> 783 <div class="neonfront_constituent_body container-lg"> 784 <!DOCTYPE html> 785<html lang="en"> 786<body> 787<div> 788 <div> 789 790 <div class="neonfront_container neonfront-login"> 791 <div class="col-12" id="neonj-page-1"> 792 <div class="row g-3 neonfront-form"> 793 794 795 <div class="col-md-12 neonfront_element"> 796 <div class="login-portal-section-title">Welcome Back!</div> 797 <label class="section-label fs-6 login-title">Log in to your account</label> 798 </div> 799 <div class="col-md-12 neonfront_element"> 800 <div class="row g-2 justify-content-center"> 801 <div class="col login-portal-description">Thank you for logging into CMA's constituent portal. Sign in here if you are a current member. If you are a current or returning member you already have an account with us. To create your login, please select "Having trouble logging in?" and you will be matched to your account. </div> 802 </div> 803 </div> 804 <div class="col-md-12 neonfront_element mt-0"> 805 <div id="globalError" class="row mt-3 neonfront-portal neonfront_form_failed_container" v-show="globalError"> 806 <div class="col-2">
807 <span class="fa fa-exclamation-circle mt-1" style="font-size: 2.25rem;"></span> 808 </div> 809 <div class="col-10"> 810 <h5 class="fs-6 mb-1" style="line-height: 42px">{{globalError}}</h5> 811 </div> 812 </div> 813 </div> 814 <div class="neonfront_element col-md-12"> 815 <label for="loginName" class="form-label">Username or Email</label> 816 <input id="loginName" v-model="loginName" name="currentPwd" type="text" @input="loginNameError = ''" class="form-control neonfront_input" :class="{'is-invalid': loginNameError}" data-testid="field-login-name"> 817 <div class="invalid-feedback"> 818 <div><i class="fa fa-exclamation-triangle"></i> 819 Username or Email is required. 820 </div> 821 </div> 822 </div> 823 <div class="neonfront_element col-md-12 login-password-field"> 824 <label for="password" class="form-label">Password</label> 825 <input id="password" v-model="password" name="password" type="password" @input="passwordError = ''" class="form-control neonfront_input" :class="{'is-invalid': passwordError}" data-testid="field-password"> 826 <i class="fas fa-eye-slash presentation" v-if="!showPassword" @click="showPsd(true)"></i> 827 <i class="fas fa-eye presentation" v-if="showPassword" @click="showPsd(false)"></i> 828 <div class="invalid-feedback"> 829 <div><i class="fa fa-exclamation-triangle"></i>Password is required.</div> 830 </div> 831 </div> 832 <div class="neonfront_element col-md-12 login-additional"> 833 <div class="form-check login-remember-me"> 834 <input class="form-check-input neonfront_checkbox" type="checkbox" value="yes" id="persistCookie" v-model="persistCookie"> 835 <label class="form-check-label neonfront_checkbox_label" for="persistCookie"> 836 Remember me for 2 weeks 837 </label> 838 </div> 839 <div class="trouble-login"> 840 <a href="/requestPassword" data-testid="link-forgot-password">Having trouble logging in?</a> 841 842 </div> 843 </div> 844 <div class="col-md-12 neonfront_element"> 845 <div class="row g-2 justify-content-center"> 846 <div class="col"> 847 <button type="button" class="btn neonfront-btn-primary btn-lg" @click="login" v-show="!loading" data-testid="bt
847n-login">Login</button> 848 <button class="btn neonfront-btn-primary btn-lg" type="button" disabled v-show="loading"> 849 Processing <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 850 </button> 851 </div> 852 </div> 853 </div> 854 <div class="col-md-12 neonfront_element login-separate"> 855 <div class="separate-line"></div> 856 <div class="separate-text">or</div> 857 <div class="separate-line"></div> 858 </div> 859 860 <div class="col-md-12 neonfront_element"> 861 <div class="create-account"> 862 Don't have an account? 863 <a v-if="activeTab === 0 || autoMergeOn" href="/forms/createaccount">Create an account</a> 864 <a v-else href="javascript:void(0)" @click="createFundraiser">Create an account</a> 865 </div> 866 </div> 867 868 </div> 869 </div> 870 </div> 871 </div> 872</div> 873<div class="modal fade neonfront-modal landing-page-login-modal" aria-hidden="true" id="fundraiserLoginModal" ref="createP2pAcctModal" data-bs-backdrop="static" tabindex="-1"> 874 <div class="modal-dialog" style="max-width: 580px;"> 875 <div class="modal-content px-sm-4 px-1"> 876 <div class="modal-header"> 877 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 878 </div> 879 880 <div class="modal-body" style="padding-top:0;padding-bottom:0"> 881 <div class="row mt-1"> 882 <div class="col login-body-title p2p-login-body-title"> 883 Create an Account 884 </div> 885 </div> 886 <div class="row mt-1"> 887 <div class="login-body-col"> 888 <div class="body-line" style="display: flex"> 889 <span> 890 <label for="firstName" class="input-label">First Name *</label> 891 <input type="text" v-model="acctData.firstName" id="firstName" name="firstName" class="form-control half-line" :class="{'invalid': acctRules.fname.invalid}" @blur="checkAcctFieldVal($event, acctRules.fname)" /> 892 <div v-if="acctRules.fname.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.fname.errMsg}}</div> 893 </span> 894 <span style="margin-left: 30px;"> 895 <label for="lastName" class="input-label">Last Name *</label> 896 <input type="text" v-model="acctData.lastName" class="form-control half-line" id="lastName" name="lastName" :class="{'invalid': acctRules.lname.invalid}" @blur="checkAcctFieldVal($event, acctRules.lname)" /> 897 <div v-if="acctRules.lname.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.lname.errMsg}}</div> 898 </span> 899 </div> 900 <div class="body-line"> 901 <label for="emailAddress" class="input-label" >Email Address *</label> 902 <input type="text" v-model="acctData.email" class="form-control" id="emailAddress" name="emailAddress" :class="{'invalid': acctRules.email.invalid}" @blur="checkAcctFieldVal($event, acctRules.email)" /> 903 <div v-if="acctRules.email.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.email.errMsg}}</div> 904 </div> 905 <div class="body-line"> 906 <label for="createPassword" class="input-label">Create Password *</label> 907 <input type="password" v-model="acctData.password" class="form-control" id="createPassword" name="createPassword" :class="{'invalid': acctRules.psd1.invalid}" @blur="checkAcctFieldVal($event, acctRules.psd1)"/>
908 <span> 909 <i class="fa fa-info-circle"></i> 910 <span class="info-message-text">Enter at least 8 characters, including at least one number. Spaces not allowed.</span> 911 </span> 912 <i class="fas fa-eye-slash presentation1" v-if="!showCreatePassword" @click="showCreatePsd(true)"></i> 913 <i class="fas fa-eye presentation1" v-if="showCreatePassword" @click="showCreatePsd(false)"></i> 914 <div v-if="acctRules.psd1.invalid" class="field-err-msg" style="margin-top: -1.25rem"><i class="fa fa-exclamation-triangle"></i>{{acctRules.psd1.errMsg}}</div> 915 </div> 916 <div class="body-line" style="margin-top: -20px;margin-bottom: 0px !important;"> 917 <label for="confirmPassword" class="input-label">Confirm Password *</label> 918 <input type="password" class="form-control" id="confirmPassword" name="confirmPassword" :class="{'invalid': acctRules.psd2.invalid}" @blur="checkAcctFieldVal($event, acctRules.psd2)"/> 919 <i class="fas fa-eye-slash presentation2" v-if="!showConfirmPassword" @click="showConfirmPsd(true)"></i> 920 <i class="fas fa-eye presentation2" v-if="showConfirmPassword" @click="showConfirmPsd(false)"></i> 921 <div v-if="acctRules.psd2.invalid" class="field-err-msg" style="margin-top:-17px;"><i class="fa fa-exclamation-triangle"></i>{{acctRules.psd2.errMsg}}</div> 922 </div> 923 924 <div v-if="gdprSettings.profileEnabled || gdprSettings.statementEnabled" class="body-line"> 925 <label class="input-label">Data Privacy & Consent</label> 926 <div class="gdpr-setting-section"> 927 <div class="gdpr-setting-items"> 928 <div v-if="gdprSettings.email" class="gdpr-setting-item neonfront_element"> 929 <div class="checkbox-column"> 930 <input v-model="gdprValues.email" type="checkbox" id="gdpr.email" name="gdpr.email" class="form-check-input neonfront_checkbox"/> 931 </div> 932 <label for="gdpr.email" class="setting-item-label">{{gdprSettings.email}}</label> 933 </div> 934 <div v-if="gdprSettings.phone" class="gdpr-setting-item neonfront_element"> 935 <div class="checkbox-column"> 936 <input v-model="gdprValues.phone" type="checkbox" id="gdpr.phone" name="gdpr.phone" class="form-check-input neonfront_checkbox"/> 937 </div> 938 <label for="gdpr.email" class="setting-item-label">{{gdprSettings.phone}}</label> 939 </div> 940 <div v-if="gdprSettings.mail" class="gdpr-setting-item neonfront_element"> 941 <div class="checkbox-column"> 942 <input v-model="gdprValues.mail" type="checkbox" id="gdpr.mail" name="gdpr.mail" class="form-check-input neonfront_checkbox"/> 943 </div> 944 <label for="gdpr.mail" class="setting-item-label">{{gdprSettings.mail}}</label> 945 </div> 946 <div v-if="gdprSettings.sms" class="gdpr-setting-item neonfront_element"> 947 <div class="checkbox-column"> 948 <input v-model="gdprValues.sms" type="checkbox" id="gdpr.sms" name="gdpr.sms" class="form-check-input neonfront_checkbox"/> 949 </div> 950 <label for="gdpr.sms" class="setting-item-label">{{gdprSettings.sms}}</label> 951 </div> 952 <div v-show="gdprValues.sms" class="smsPhoneNum-section" style="padding-left:25px"> 953 <label for="smsPhoneNum" class="input-label">What's the best number for us to text you? *</label> 954 <input v-model="gdprValues.smsPhoneNum" type="text" class="form-control" id="smsPhoneNum" name="smsPhoneNum" :class="{'invalid': gdprValues.smsPhoneInvalid}" @blur="checkGdprSmsPhoneNum($event)"/> 955 <div v-if="gdprValues.smsPhoneInvalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{gdprValues.smsPhoneInvalidMsg}}</div> 956 </div> 957 <div v-if="gdprSettings.share" class="gdpr-setting-item neonfront_element"> 958 <div class="checkbox-column"> 959 <input v-model="gdprValues.share" type="checkbox" id="gdpr.share" name="gdpr.share" class="form-check-input neonfront_checkbox"/> 960 </div> 961 <label for="gdpr.share" class="setting-item-label">{{gdprSettings.share}}</label> 962 </div> 963 </div> 964 965 <div v-if="gdprSettings.statement" class="gdpr-statement"> 966 {{gdprSettings.statement}} 967 </div> 968 <div v-if="gdprSettings.policyUrl" class="gdpr-policy"> 969 <a :href="gdprSettings.policyUrl" target="_blank" style="text-decoration: none">{{gdprSettings.policyLabel}}</a> 970 </div> 971 </div> 972 </div> 973 </div> 974 </div> 975 </div> 976 <div class="login-footer p2p-login-footer"> 977 <button v-if="!doCreateAcct" type="button" 978 class="btn neonfront-btn-primary btn-lg p2p-btn" 979 :disabled="checkCreateAcctField" 980 @click="doP2pCreateAccount">Submit</button> 981 <button v-if="doCreateAcct" class="btn neonfront-btn-primary btn-lg p2p-btn" type="button" disabled> 982 Processing <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 983 </button> 984 <div class="col-md-12 neonfront_element login-separate p2p_login_separate"> 985 <div class="separate-line"></div> 986 <div class="separate-text">or</div> 987 <div class="separate-line"></div> 988 </div> 989 <div class="go_login_sty">Have an account? <a href="javascript:void(0)" data-bs-dismiss="modal">Log in</a></div> 990 </div> 991 </div> 992 </div> 993</div> 994 995</body> 996</html> 997 998 </div> 999 </div> 1000 </div> 1001 </div> 1002 </div> 1003 </div> 1004 <!DOCTYPE html> 1005<html> 1006<body> 1007 <div class="container-fluid neonfront_footer" id="footer-content"> 1008 <div class="row neonfront_footer_lv_info"> 1009 <div v-if="theme.footerColumns==1" class="col-md-12" style="padding-left:30px;padding-right:30px;"> 1010 <div v-html="theme.footerCol1Text"></div> 1011 </div> 1012 <div v-if="theme.footerColumns==2" class="col-md-6" style="padding-left:30px;"> 1013 <div class="float-md-start float-none" v-html="theme.footerCol1Text"></div> 1014 </div> 1015 <div v-if="theme.footerColumns==2" class="col-md-6" style="padding-right:30px;"> 1016 <div class="float-md-end float-none" v-html="theme.footerCol2Text"></div> 1017 </div> 1018 <div v-if="theme.footerColumns==3" class="col-md-4" style="padding-left:30px;"> 1019 <div class="float-md-start float-none" v-html="theme.footerCol1Text"></div> 1020 </div> 1021 <div v-if="theme.footerColumns==3" class="col-md-4 text-md-center footer_center_column"> 1022 <div class="footer_center_column_content" style="margin:0 auto;" v-html="theme.footerCol2Text"></div> 1023 </div> 1024 <div v-if="theme.footerColumns==3" class="col-md-4" style="padding-right:30px;"> 1025 <div class="float-md-end float-none" v-html="theme.footerCol3Text"></div> 1026 </div> 1027 </div> 1028 <div v-if="theme.displaySocialLink" 1029 :class="['neonfront_footer_lv_media', 1030 theme.socialLinkIconAlign==='C' ? 'text-center' : (theme.socialLinkIconAlign==='R' ? 'text-end' : 'text-start'), 1031 theme.socialLinkIconStyle==='L' ? 'text-white' : 'text-dark']"> 1032 <template v-for="item in (theme.socialLinks||[])" :key="item.icon"> 1033 <a v-if="item.url" 1034 :href="item.icon==='Email' ? 'mailto:'+item.url : (item.url.startsWith('http://') || item.url.startsWith('https://') || item.url.startsWith('//') ? item.url : 'https://'+item.url)" 1035 :style="theme._previewMode ? {'pointer-events': 'none'} : {}" 1036 target="_blank" 1037 class="text-reset social-link-icon"> 1038 <img width="24" height="24" 1039 :src="getSocialMediaIcon(item.icon, theme.socialLinkIconStyle)"> 1040 </a> 1041 </template> 1042 </div> 1043 1044 <div class="footer-root"> 1045 <div class="footer-root-left"><a class="footer-root-link" href="https://neonone.com/privacypolicy/" target="_blank">Privacy Statement</a> | <a class="footer-root-link" href="https://neonone.com/productterms/" target="_blank">Terms of Service</a></div> 1046 <div class="footer-root-right"> 1047 <a href="https://neonone.com/" target="_blank"> 1048 <div class="footer-root-right-header"><img width="60" height="20" src="/nx/portal-static/img/logo-variations.svg"/></div> 1049 <div class="footer-root-right-footer"><img width="60" height="20" src="/nx/portal-static/img/merchant-copy.svg"/></div> 1050 </a> 1051 </div> 1052 </div> 1053 </div> 1054</body> 1055</html> 1056 </div> 1057 1058 1059 <!DOCTYPE html> 1060<html lang="en"> 1061<body> 1062 <!DOCTYPE html> 1063<html lang="en"> 1064<body> 1065<!-- Modal --> 1066<div class="modal fade neonfront-modal neonfront-confirm-modal" id="confirmSubMembershipEndModal" data-bs-backdrop="static" tabindex="-1"> 1067 <div class="modal-dialog" style="max-width: 580px;"> 1068 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1069 <div class="modal-header"> 1070 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelSubMembershipEndTurnOff"></button> 1071 </div> 1072 <div class="modal-body"> 1073 <div class="row mt-1"> 1074 <div class="col"> 1075 <div>Are you sure you want to end the selected sub-membership? This action will set the End Date to one day in the past.</div> 1076 </div> 1077 </div> 1078 </div> 1079 <div class="modal-footer"> 1080 <button type="button" class="btn btn-link neonfront-btn-l
1080ink" @click="cancelSubMembershipEndTurnOff" style="width: auto">Cancel</button> 1081 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmSubMembershipEndTurnOff" style="width: auto">Confirm</button> 1082 </div> 1083 </div> 1084 </div> 1085</div> 1086</body> 1087</html> 1088 <!DOCTYPE html> 1089<html lang="en"> 1090<body> 1091<!-- Modal --> 1092<div class="modal fade neonfront-modal neonfront-confirm-modal" id="addressListDeleteModal" data-bs-backdrop="static" tabindex="-1"> 1093 <div class="modal-dialog" style="max-width: 580px;"> 1094 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1095 <div class="modal-header"> 1096 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelAddressListDeleteModal"></button> 1097 </div> 1098 <div class="modal-body"> 1099 <div class="row mt-1"> 1100 <div class="col"> 1101 <p>Are you sure you want to delete this address?</p> 1102 <p class="desc">Your address will be deleted.</p> 1103 </div> 1104 </div> 1105 </div> 1106 <div class="modal-footer"> 1107 <button type="button" class="btn btn-link neonfront-btn-link" @click="cancelAddressListDeleteModal" style="width: auto">Cancel</button> 1108 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmAddressListDeleteModal" style="width: auto">Confirm</button> 1109 </div> 1110 </div> 1111 </div> 1112</div> 1113</body> 1114</html> 1115 <!DOCTYPE html> 1116<html lang="en"> 1117<body> 1118<!-- Modal --> 1119<div class="modal fade neonfront-modal neonfront-confirm-modal" id="addressListCommonDeleteModal" data-bs-backdrop="static" tabindex="-1"> 1120 <div class="modal-dialog" style="max-width: 580px;"> 1121 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1122 <div class="modal-header"> 1123 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelAddressListDeleteModal"></button> 1124 </div> 1125 <div class="modal-body"> 1126 <div class="row mt-1"> 1127 <div class="col"> 1128 <p>Address cannot be deleted because of the following linked data:</p> 1129 <p class="desc" v-for="item in deleteInfo"> 1130 {{decisionDeleteInfo(item)}} 1131 </p> 1132 </div> 1133 </div> 1134 </div> 1135 <div class="modal-footer"> 1136 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="cancelAddressListCommonDeleteModal" style="width: auto;margin-left: auto">Close</button> 1137 </div> 1138 </div> 1139 </div> 1140</div> 1141</body> 1142</html> 1143</body> 1144</html> 1145 1146 <div class="modal fade neonfront-modal" id="goP2pConfirmModal" data-bs-backdrop="static" tabindex="-1"> 1147 <div class="modal-dialog"> 1148 <div class="modal-content px-sm-4 px-1 go-p2p-confirm-modal"> 1149 <div class="header"> 1150 Leaving this Page 1151 </div> 1152 <div class="content"> 1153 You are about to be redirected to another portal to manage your Peer-to-Peer Fundraising pages. You can return to this portal at any time. 1154 <br/><br/>Do you want to continue? 1155 </div> 1156 <div class="footer"> 1157 <button type="button" class="btn btn-link neonfront-btn-link" @click="cancelP2pConfirmModal()" 1158 style="width: auto; font-family: var(--page-font, Lato)">Cancel 1159 </button> 1160 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmP2pConfirmModal" 1161 style="width: auto; font-family: var(--page-font, Lato)">Continue 1162 </button> 1163 </div> 1164 <i class="fa-solid fa-xmark-large close_icon" @click="cancelP2pConfirmModal"></i> 1165 </div> 1166 </div> 1167</div> 1168 1169</div> 1170
1171<script src="/nx/portal-static/component/vue/vue-3.1.2.min.js"></script>
vendor: 1 bytes, line 1171
1171
1172<script src="/nx/portal-static/component/axios/axios.min.js"></script>
vendor: 1 bytes, line 1172
1172
1173<script src="/nx/portal-static/component/qs/qs.min.js"></script>
vendor: 1 bytes, line 1173
1173
1174<script src="/nx/portal-static/component/bootstrap/js/bootstrap.bundle.min.js"></script>
vendor: 1 bytes, line 1174
1174
1175<script src="/nx/portal-static/component/laydate/laydate.js"></script>
vendor: 1 bytes, line 1175
1175
1176<script src="/nx/portal-static/component/cropperjs/cropper.min.js"></script>
vendor: 1 bytes, line 1176
1176
1177<script src="/nx/portal-static/component/moment-js/moment-2.30.1.min.js"></script>
vendor: 1 bytes, line 1177
1177
1178<script src="/nx/portal-static/component/moment-js/moment-timezone.min.js"></script>
1178 1179
1180<script src="/nx/portal-static/js/portal.all.js"></script>
1180 1181<!-- 1182<th:block th:if="${churnZeroEnabled && !#strings.isEmpty(churnZeroAccountExternalId)}">
1183<script src="https://neonone.us1app.churnzero.net/churnzero.js"></script>
vendor: 1 bytes, line 1183
1183
1184<script type="application/javascript"> 1185 var ChurnZero = ChurnZero || [] 1186 1187 ChurnZero.push(['setAppKey', '1!MFdwDlKbVUgVpSRtljcqdO9tOYWtqDKqGG7trJX5JYwtE02']) // AppKey from ChurnZero 1188 ChurnZero.push(['setContact', '', '']) 1189</script>
1189 1190</th:block> 1191--> 1192
1193<script type="application/javascript"> 1194 // Common JS Code 1195</script>
1195 1196 1197 1198 1199
1200<script> 1201 // CLP embed: notify parent on DOMContentLoaded for re-postMessage 1202 (function () { 1203 const urlParams = new URLSearchParams(window.location.search); 1204 const clpEmbedEnv = sessionStorage.getItem('clpEmbedEnv') === '1' 1205 || urlParams.get('clpEmbedEnv') === '1'; 1206 if (!clpEmbedEnv) return; 1207 const embedIframeId = urlParams.get('embedIframeId') || sessionStorage.getItem('clpEmbedIframeId'); 1208 const embedIframeDomainUrl = urlParams.get('embedIframeDomainUrl') || sessionStorage.getItem('clpEmbedDomainUrl'); 1209 if (!embedIframeId || !embedIframeDomainUrl) return; 1210 window.addEventListener('DOMContentLoaded', function () { 1211 parent.postMessage({type: 'DOMContentLoaded', embedIframeId: embedIframeId}, embedIframeDomainUrl); 1212 }); 1213 }()); 1214</script>
1214 1215
1216<script src="/nx/portal-static/js/clp-embed-content.js"></script>
vendor: 66 bytes, lines 1216-1219
1216 1217 1218 1219<script async src="https://www.googletagmanager.com/gtag/js?id=
1219G-E5PVK7VDYC
vendor: 12 bytes, line 1219
1219"></script>
1220<script> 1221
vendor: 139 bytes, lines 1221-1224
1221window.dataLayer = window.dataLayer || []; 1222 function gtag(){dataLayer.push(arguments);} 1223 gtag('js', new Date()); 1224 gtag('config', '
1224G-E5PVK7VDYC
vendor: 4 bytes, line 1224
1224');
1225</script>
vendor: 72 bytes, lines 1225-1228
1225 1226 1227 1228 <script src="https://www.google.com/recaptcha/enterprise.js?render=
12286Lciqi8rAAAAAG87Wg7usbkvyHVTXylFPgeSyHkM
vendor: 24 bytes, line 1228
1228" async defer></script>
1229<script type="text/javascript"> 1230 const appData = { 1231 showCreatePassword: false, 1232 showConfirmPassword: false, 1233 doLoginLoading: false, 1234 doCreateAcct: false, 1235 acctRules: { 1236 fname: {type: 'name', invalid: null, errMsg: 'First Name is required.'}, 1237 lname: {type: 'name', invalid: null, errMsg: 'Last Name is required.'}, 1238 email: {type: 'email', invalid: null, errMsg: 'Email Address is required.'}, 1239 psd1: {type: 'psd1', invalid: null, errMsg: 'Create Password is required.'}, 1240 psd2: {type: 'psd2', invalid: null, errMsg: 'Confirm Password is required.'} 1241 }, 1242 acctData: { 1243 firstName: '', 1244 lastName: '', 1245 email: '', 1246 password: '' 1247 }, 1248 gdprSettings: {}, 1249 autoMergeOn: false, 1250 gdprValues: { 1251 email: false, 1252 phone: false, 1253 mail: false, 1254 sms: false, 1255 share: false, 1256 smsPhoneNum: '', 1257 smsPhoneInvalid: null, 1258 smsPhoneInvalidMsg: '' 1259 }, 1260 loginName: '', 1261 password: '', 1262 persistCookie: '', 1263 loading: false, 1264 loginNameError: false, 1265 passwordError: false, 1266 globalError: '', 1267 showPassword: false, 1268 source: '', 1269 // OAuth Authorization Server handoff: literal "as" == OauthConstant.LOGIN_SOURCE / LoginSourceConstants.OAUTH_AS 1270 targetUrl:'', 1271 redirectUrl: '', 1272 fromNeonWebSite: false, 1273 embeddedLogin: false, 1274 activeTab: 0, 1275 googleReCaptchaEnabled: true, 1276 googleReCaptchaEnabled0: true, 1277 enableModernLogin: false, 1278 fromLogout: false, 1279 recaptchaResponse: null 1280 } 1281 1282 const appMethods = { 1283 tabChange(index){ 1284 this.activeTab = index 1285 }, 1286 doLogin: function () { 1287 if (this.enableModernLogin) { 1288 if (this.embeddedLogin || this.source === 'embedded') { 1289 const loginName = btoa(this.loginName) 1290 const loginPassword = btoa(this.password) 1291 const url = '/nx/auth/authenticate?source=embedded' 1292 + '&loginName=' + encodeURIComponent(loginName) 1293 + '&loginPassword=' + encodeURIComponent(loginPassword) 1294 + (this.persistCookie === true ? '&rememberMe=true' : '') 1295 window.location.href = url 1296 return 1297 } 1298 // Align with legacy signIn.do: password login does not submit/verify reCAPTCHA. 1299 this.loading = true 1300 this.globalError = '' 1301 // Modern resolves the post-login redirect server-side, so the active tab has to 1302 // travel with the request (the legacy branch below picks /p2p/overview locally). 1303 // source=as owns targetUrl â ai= is appended to it â so never overwrite it there. 1304 let target = this.targetUrl || this.redirectUrl || '' 1305 if (!target && !this.source && this.activeTab === 1) { 1306 target = '/p2p/overview' 1307 } 1308 let url = '/nx/auth/authenticate?targetUrl=' + encodeURIComponent(target); 1309 if (this.source) { 1310 url += '&source=' + encodeURIComponent(this.source); 1311 } 1312 axios.post(url, { 1313 loginName: this.loginName, 1314 password: this.password, 1315 rememberMe: this.persistCookie === true, 1316 requestId: 'c962f264-c3df-4979-8b38-1044a8bda376', 1317 source: this.source || '' 1318 }).then((res) => { 1319 const body = res.data || {}; 1320 if (body.success && body.data) { 1321 window.location = body.data.redirect; 1322 } else { 1323 this.loading = false 1324 const msgs = body.messages || []; 1325 this.globalError = (msgs[0] && msgs[0].message) || 'Login Name/Password is invali
1325d'; 1326 } 1327 }).catch(() => { 1328 this.loading = false 1329 this.globalError = 'Login Name/Password is invalid'; 1330 }); 1331 return 1332 } 1333 let $loginData = { 1334 loginName: this.loginName, 1335 loginPassword: this.password, 1336 persistCookie: this.persistCookie === true ? 'yes' : this.persistCookie, 1337 ajaxLogin: true, 1338 source: this.fromNeonWebSite? 'duda' : this.source, 1339 targetUrl: this.targetUrl || this.redirectUrl, 1340 requestId: 'c962f264-c3df-4979-8b38-1044a8bda376' 1341 } 1342 this.loading = true 1343 this.globalError = '' 1344 axios.post('/np/security/signIn.do', Qs.stringify($loginData)).then(response => { 1345 let $data = response.data 1346 if ($data.status === 'success') { 1347 if (this.loginName === 'admin') { 1348 window.location = '/np/admin/content/contentList.do' 1349 } else if ($data.succeedRedirectPath) { 1350 window.location = $data.succeedRedirectPath 1351 } else if(this.activeTab === 1) { 1352 window.location = '/p2p/overview' 1353 } else { 1354 window.location = '/constituent/dashboard' 1355 } 1356 } else { 1357 this.loading = false 1358 this.globalError = $data.errors[0] 1359 } 1360 }) 1361 }, 1362 login: function () { 1363 let validatePass = true 1364 if (Validator.required.check(this.loginName)) { 1365 this.loginNameError = true 1366 validatePass = false 1367 } 1368 if (Validator.required.check(this.password)) { 1369 this.passwordError = true 1370 validatePass = false 1371 } 1372 if (!validatePass) { 1373 return 1374 } 1375 this.passwordError = false 1376 this.loginNameError = false 1377 this.doLogin() 1378 }, 1379 1380 showPsd: function ($show) { 1381 if ($show) { 1382 this.showPassword = true 1383 document.querySelector('#password').type = 'text' 1384 } else { 1385 this.showPassword = false 1386 document.querySelector('#password').type = 'password' 1387 } 1388 }, 1389 fn_openAuthWin: function (src) { 1390 if (this.enableModernLogin) { 1391 // Same sources as password login (targetUrl / redirectUrl), plus live ?redirect= 1392 // from the address bar â Thymeleaf injection alone has been unreliable for social. 1393 const params = new URLSearchParams(window.location.search || ''); 1394 let path = (params.get('redirect') 1395 || params.get('target') 1396 || this.targetUrl 1397 || this.redirectUrl 1398 || '').trim(); 1399 if (path) { 1400 try { 1401 path = decodeURIComponent(path); 1402 } catch (e) { /* keep raw */ } 1403 } 1404 if (!path) { 1405 path = window.location.pathname + window.location.search; 1406 const pathOnly = (window.location.pathname || '').replace(/\/+$/, '') || '/'; 1407 if (pathOnly === '/login' || pathOnly === '/nx/login' || /\/login$/.test(pathOnly)) { 1408 path = '/'; 1409 } 1410 } 1411 neonSocialLogin(src, { 1412 targetUrl: path, 1413 orgId: this.orgId, 1414 // Literal "as" == OauthConstant.LOGIN_SOURCE / LoginSourceConstants.OAUTH_AS 1415 custom: this.source === 'as' ? 'as' : undefined 1416 }); 1417 return; 1418 } 1419 const path = "/np/clients/" + this.orgId + "/snOpenAuthWin.do?"; 1420 const param = "src=" + src + "&da=login"+ (this.fromNeonWebSite?'&custom=duda':''); 1421 const url = path + param; 1422 const size = 'width=750,height=450,top=230,left=370,toolbar=no'; 1423 window.location.href = url; 1424 }, 1425 enterClick: function (e) { 1426 if (e.keyCode === 13) { 1427 if (e.target.closest('.neonfront_input')) { 1428 this.login() 1429 } 1430 if (e.target.closest('.form-check-input')) { 1431 this.login() 1432 } 1433 } 1434 }, 1435 listenEnterKey: function () { 1436 document.addEventListener('keydown', this.enterClick) 1437 }, 1438 createFundraiser: function () { 1439 this.doLoginLoading = false 1440 this.doCreateAcct = false 1441 this.p2pLoginErrorMessages = []
1442 this.acctRules.fname.invalid = null 1443 this.acctRules.lname.invalid = null 1444 this.acctRules.email.invalid = null 1445 this.acctRules.psd1.invalid = null 1446 this.acctRules.psd2.invalid = null 1447 this.$nextTick(() => { 1448 const modalElement = this.$refs.createP2pAcctModal; 1449 document.body.appendChild(modalElement); 1450 const modal = new bootstrap.Modal(this.$refs.createP2pAcctModal) 1451 modal.show() 1452 }) 1453 }, 1454 invisibleReCaptchaInit: function () { 1455 window.ReCaptchaLoaded = this.reCaptchaCallback; 1456 let tag = document.createElement("div") 1457 tag.className = 'g-recaptcha' 1458 document.body.appendChild(tag); 1459 let timer = setInterval(() => { 1460 if(window.grecaptcha && grecaptcha.enterprise && typeof window.grecaptcha.enterprise.render === 'function'){ 1461 window.grecaptcha.enterprise.render(tag,{ 1462 sitekey: '6Lciqi8rAAAAAG87Wg7usbkvyHVTXylFPgeSyHkM', 1463 size: 'invisible' 1464 }); 1465 clearInterval(timer); 1466 } 1467 },500); 1468 }, 1469 reCaptchaCallback: function ($token) { 1470 this.recaptchaResponse = $token 1471 if(window.grecaptcha && window.grecaptcha.enterprise) { 1472 window.grecaptcha.enterprise.reset() 1473 } 1474 this.doP2pCreateAccountSendToServer() 1475 }, 1476 validateReCaptcha:function () { 1477 if(window.grecaptcha && window.grecaptcha.enterprise) { 1478 this.recaptchaResponse = null 1479 window.grecaptcha.enterprise.execute().then(($token) => { 1480 this.reCaptchaCallback($token) 1481 }) 1482 } else { 1483 this.doP2pCreateAccountSendToServer() 1484 } 1485 }, 1486 doP2pCreateAccount: function () { 1487 this.doCreateAcct = true 1488 this.validateReCaptcha() 1489 }, 1490 doP2pCreateAccountSendToServer: function () { 1491 let formData = new FormData(); 1492 formData.append('firstName', this.acctData.firstName.trim()); 1493 formData.append('lastName', this.acctData.lastName.trim()); 1494 formData.append('email', this.acctData.email.trim()); 1495 formData.append('password', this.acctData.password.trim()); 1496 formData.append('recaptchaResponse', this.recaptchaResponse); 1497 if (this.gdprSettings.profileEnabled) { 1498 formData.append('gdpr.email', this.gdprValues.email); 1499 formData.append('gdpr.phone', this.gdprValues.phone); 1500 formData.append('gdpr.mail', this.gdprValues.mail); 1501 formData.append('gdpr.sms', this.gdprValues.sms); 1502 formData.append('gdpr.share', this.gdprValues.share); 1503 formData.append('gdpr.smsPhoneNum', this.gdprValues.smsPhoneNum); 1504 } 1505 axios.post('/nx/portal/p2p-data/create-account', formData, {}).then(response => { 1506 if (response.data.success) { 1507 this.doP2pLogin(this.acctData.email, this.acctData.password) 1508 } else { 1509 alert(response.data.messages[0].message); 1510 this.doCreateAcct = false 1511 } 1512 }).catch(error => { 1513 console.log(error) 1514 this.doCreateAcct = false 1515 alert('Create account failed, please try again.') 1516 }) 1517 }, 1518 doP2pLogin: function (name, password) { 1519 this.doLoginLoading = true 1520 if (this.enableModernLogin) { 1521 // Align with legacy: password login does not submit/verify reCAPTCHA. 1522 let url = '/nx/auth/authenticate?targetUrl=' + encodeURIComponent('/p2p/overview') 1523 axios.post(url, { 1524 loginName: name, 1525 password: password, 1526 requestId: 'c962f264-c3df-4979-8b38-1044a8bda376' 1527 }).then((res) => { 1528 const body = res.data || {}; 1529 if (body.success && body.data) { 1530 window.location.href = body.data.redirect; 1531 } else { 1532 const msgs = body.messages || []; 1533 this.globalError = (msgs[0] && msgs[0].message) || 'Login failed'; 1534 alert(this.globalError) 1535 } 1536 this.doCreateAcct = false 1537 this.doLoginLoading = false 1538 }).catch((error) => { 1539 console.error(error.response) 1540 alert('Login error: ' + JSON.stringify(error.response)) 1541 this.doLoginLoading = false 1542 }) 1543 return 1544 } 1545 let params = { 1546 loginName: name, 1547 loginPassword: password, 1548 orgId: 'chambermusicamerica', 1549 ajaxLogin: true,
1550 requestId: 'c962f264-c3df-4979-8b38-1044a8bda376' 1551 } 1552 axios.post('/np/security/encouragedSignIn.do', Qs.stringify(params)).then(response => { 1553 let result = response.data 1554 if (result.status === 'success') { 1555 window.location.href = 'https://' + window.location.host + '/p2p/overview' 1556 } else { 1557 alert('Login error: ' + JSON.stringify(result.errors)) 1558 } 1559 this.doCreateAcct = false 1560 this.doLoginLoading = false 1561 }).catch(error => { 1562 console.error(error.response) 1563 alert('Login error: ' + JSON.stringify(error.response)) 1564 this.doLoginLoading = false 1565 }) 1566 }, 1567 checkAcctFieldVal: function ($event, rule) { 1568 let val = $event.target.value.trim(); 1569 if (rule.type === 'name' && !val) { 1570 rule.invalid = true 1571 } else if (rule.type === 'email' && !val) { 1572 rule.errMsg = 'Email Address is required.' 1573 rule.invalid = true 1574 } else if (rule.type === 'email' && Validator['email'].check(val)) { 1575 rule.errMsg = 'Email Address format is invalid.' 1576 rule.invalid = true 1577 } else if (rule.type === 'psd1' && !val) { 1578 rule.errMsg = 'Create Password is required.' 1579 rule.invalid = true 1580 } else if (rule.type === 'psd1' && Validator.password.check(val)) { 1581 rule.errMsg = 'Your password requires at least 8 characters, including at least one number. Spaces are not allowed.' 1582 rule.invalid = true 1583 } else if (rule.type === 'psd2') { 1584 if (val) { 1585 let val1 = document.querySelector('#createPassword').value 1586 rule.errMsg = 'Confirm Password does not match.' 1587 rule.invalid = (val !== val1.trim()) 1588 } else { 1589 rule.errMsg = 'Confirm Password is required.' 1590 rule.invalid = true 1591 } 1592 } else { 1593 rule.invalid = false 1594 } 1595 }, 1596 showConfirmPsd: function ($show) { 1597 if ($show) { 1598 this.showConfirmPassword = true 1599 document.querySelector('#confirmPassword').type = 'text' 1600 } else { 1601 this.showConfirmPassword = false 1602 document.querySelector('#confirmPassword').type = 'password' 1603 } 1604 }, 1605 showCreatePsd: function ($show) { 1606 if ($show) { 1607 this.showCreatePassword = true 1608 document.querySelector('#createPassword').type = 'text' 1609 } else { 1610 this.showCreatePassword = false 1611 document.querySelector('#createPassword').type = 'password' 1612 } 1613 }, 1614 loadGdprSetting: function () { 1615 let previewMode = false 1616 if (previewMode) { 1617 return; 1618 } 1619 axios.get('/nx/portal/p2p-data/login-settings').then(response => { 1620 if (response.data.success) { 1621 this.gdprSettings = response.data.data.gdprSettings 1622 this.autoMergeOn = response.data.data.autoMergeOn 1623 } 1624 }).catch(error => { 1625 alert('Load GDPR settings failed, please try again.') 1626 }) 1627 }, 1628 checkGdprSmsPhoneNum: function ($event) { 1629 let val = $event.target.value.trim(); 1630 if (!val) { 1631 this.gdprValues.smsPhoneInvalid = true 1632 this.gdprValues.smsPhoneInvalidMsg = 'The SMS/MMS Number is required.' 1633 return 1634 } 1635 let usPhoneReg = /^(\+?1[-\s]?)?\(?[2-9]\d{2}\)?[-\s]?[2-9](?!11)\d{2}[-\s]?\d{4}$/ 1636 if (!usPhoneReg.test(val.replace(/\s+/g, ''))) { 1637 this.gdprValues.smsPhoneInvalid = true 1638 if (val.replace(/[\s\-()]/g, '').match(/^[^1]\d{10}$/)) { 1639 this.gdprValues.smsPhoneInvalidMsg = '11-digit numbers must begin with the country code 1 (US/Canada).' 1640 } else { 1641 this.gdprValues.smsPhoneInvalidMsg = 'Please enter a valid 10 or 11 digit mobile number.' 1642 } 1643 return 1644 } 1645 this.gdprValues.smsPhoneInvalid = false 1646 this.gdprValues.smsPhoneInvalidMsg = '' 1647 } 1648 } 1649 1650 const appComputed = { 1651 checkCreateAcctField: function () {
1652 return !(this.acctRules.fname.invalid === false && this.acctRules.lname.invalid === false 1653 && this.acctRules.email.invalid === false && this.acctRules.psd1.invalid === false 1654 && this.acctRules.psd2.invalid === false && (!this.gdprValues.sms || (this.gdprValues.smsPhoneNum && this.gdprValues.smsPhoneInvalid === false))) 1655 }, 1656 } 1657 1658 const appWatch = {} 1659 1660 const appConfig = { 1661 data: function () { 1662 return appData 1663 }, 1664 methods: appMethods, 1665 computed: appComputed, 1666 watch: appWatch, 1667 created: function() { 1668 const params = new URLSearchParams(window.location.search); 1669 const activeTab = params.get('activeTab'); 1670 if(activeTab === '1') { 1671 this.activeTab = 1 1672 } 1673 }, 1674 mounted: function () { 1675 if(this.googleReCaptchaEnabled || this.googleReCaptchaEnabled0) { 1676 this.invisibleReCaptchaInit() 1677 } 1678 this.listenEnterKey() 1679 this.loadGdprSetting() 1680 } 1681 } 1682</script>
1682 1683 1684 1685
1686<script type="application/javascript"> 1687 appData.loggedIn = false 1688 appData.previewMode = false 1689 appData.orgId = 'chambermusicamerica' 1690 appData.currentAccountId = 1691 appData.accountBasicInfo = '' 1692 appData.profilePhoto = { 1693 url: '', 1694 approved: false 1695 } 1696 appData.showMenu = false 1697 appData.formCurrency= '$' 1698 appData.formCurrencyCode= 'USD' 1699 appData.theme = window._neonThemeData || {} 1700 appMethods.formatAmount = function (amount) { 1701 return Formatter.numberFormat(amount, 2, this.formCurrency) 1702 } 1703 appMethods.showP2pConfirmModal = function() { 1704 bootstrap.Modal.getInstance(document.getElementById("goP2pConfirmModal")).show() 1705 } 1706 appMethods.cancelP2pConfirmModal = function(){ 1707 bootstrap.Modal.getInstance(document.getElementById("goP2pConfirmModal")).hide() 1708 } 1709 appMethods.confirmP2pConfirmModal = function(){ 1710 window.location.href='/p2p/overview' 1711 } 1712 appMethods.getSocialMediaIcon = function (name, style) { 1713 if (typeof getSocialIconURL === 'function') return getSocialIconURL(name, style) 1714 // legacy fallback 1715 return style === 'D' 1716 ? '/nx/static/img/icons/social-media/darkicons/' + name + '.svg' 1717 : '/nx/static/img/icons/social-media/lighticons/' + name + '.svg' 1718 } 1719 // Add interceptor for portal page 1720 axios.interceptors.request.use(function (config) { 1721 if(appData.previewMode){ 1722 config.url = config.url.replace('/portal/constituent','/admin/portal/fake').replace('/portal/p2p','/admin/portal/fake/p2p').replace('/portal/event-list','/admin/portal/fake/event-list') 1723 } 1724 return config 1725 }, function (error) { 1726 // ... 1727 return Promise.reject(error) 1728 }); 1729 1730 (function (){ 1731 if(window.location.href.includes('/constituent')){ 1732 window.addEventListener( "pageshow", function ( $event ) { 1733 const performanceNavigationTiming = performance.getEntriesByType('navigation')[0]; 1734 // performanceNavigationTiming.type === 'back_forward' for firefox 1735 const historyTraversal = $event.persisted || performanceNavigationTiming.type === 'back_forward'; 1736 if ( historyTraversal ) { 1737 window.location.reload(); 1738 } 1739 }); 1740 } 1741 })(); 1742 const originalMounted = appConfig.mounted 1743 appConfig.mounted = function() { 1744 const result = originalMounted.apply(this); 1745 const $dom = document.getElementById("goP2pConfirmModal") 1746 if($dom) { 1747 new bootstrap.Modal($dom) 1748 } 1749 return result 1750 } 1751 appWatch.theme = { 1752 handler: function(newVal) { 1753 if (typeof applyThemeCSSVars === 'function') applyThemeCSSVars(newVal) 1754 }, 1755 deep: true 1756 } 1757 const vueApp = Vue.createApp(appConfig) 1758 vueApp.config.errorHandler = function (err, vm, info) { 1759 if (handleVueJSError) { 1760 handleVueJSError(err, vm, info) 1761 } 1762 console.log(err) 1763 } 1764 vueApp.component('neon-multiselect', window.NeonMultiselect) 1765 vueApp.component('neon-search-box', window.NeonSearchBox) 1766 vueApp.component('neon-fileupload', window.NeonFileupload) 1767 vueApp.component('neon-advancedsearch', window.NeonAdvancedsearch) 1768 vueApp.component('neon-select', window.NeonSelect) 1769 vueApp.component('neon-img-cutter', window.NeonImgCutter) 1770 vueApp.component('neon-pagination', window.NeonPagination) 1771 vueApp.component('neon-pagination-plus', window.NeonPaginationPlus) 1772 vueApp.component('neon-share-modal', window.NeonShareModal) 1773 vueApp.component('neon-search-select', window.NeonSearchSelect) 1774 vueApp.component('neon-search-location', window.NeonSearchLocation) 1775 vueApp.component('neon-input', window.NeonInput) 1776 const app = vueApp.mount('#app') 1777 window.__neonApp = app 1778</script>
1778 1779 1780 1781 1782
1782<script type="text/javascript"> 1783 function setSliderBar(func , wait , immediate) { 1784 let timeout 1785 return function () { 1786 let context = this, args = arguments 1787 let later = function() { 1788 timeout = null 1789 if (!immediate) func.apply(context, args) 1790 } 1791 let callNow = immediate & !timeout 1792 clearTimeout(timeout); 1793 timeout = setTimeout(later, wait); 1794 if (callNow) func.apply(context, args) 1795 } 1796 } 1797 function fixSliderBar() { 1798 let maxWidth = document.body.clientWidth 1799 const leftBar = document.getElementById("left-nav") 1800 const content = document.getElementById("content") 1801 const rightContent = document.getElementById("right-content") 1802 const footContent = document.getElementById("footer-content") 1803 const fixedTitle = document.getElementById("fixed-title") 1804 const flexRow = rightContent.parentNode 1805 const clientHeight = window.innerHeight 1806 if (maxWidth >= 992) { 1807 let isClpEmbed = false 1808 try { 1809 isClpEmbed = sessionStorage.getItem('clpEmbedEnv') === '1' 1810 || new URLSearchParams(window.location.search).get('clpEmbedEnv') === '1' 1811 } catch (e) { 1812 } 1813 if (isClpEmbed) { 1814 leftBar.style.position = 'static' 1815 leftBar.style.top = '' 1816 leftBar.style.bottom = '' 1817 leftBar.style.height = '' 1818 leftBar.style.minHeight = '' 1819 leftBar.style.left = '' 1820 leftBar.style.width = '' 1821 flexRow.style.paddingLeft = '' 1822 rightContent.style.marginLeft = '' 1823 rightContent.style.minHeight = '0' 1824 try { 1825 fixedTitle.style.display = 'none' 1826 } catch (e) { 1827 } 1828 leftBar.style.maxHeight = '' 1829 leftBar.style.overflow = '' 1830 const contentHeight = rightContent.offsetHeight 1831 if (contentHeight > 0 && leftBar.scrollHeight > contentHeight) { 1832 leftBar.style.maxHeight = contentHeight + 'px' 1833 leftBar.style.overflow = 'hidden auto' 1834 } 1835 return 1836 } 1837 if (leftBar.getBoundingClientRect().top <= 0) { 1838 //float in top on footer 1839 const footerHidden = footContent.offsetHeight === 0 1840 let heightVary = footContent.getBoundingClientRect().bottom - clientHeight 1841 let varyHeight = footContent.offsetHeight - heightVary 1842 if (!footerHidden && varyHeight >= 0 && heightVary <= footContent.offsetHeight) { 1843 //footer show 1844 if(!leftBar.classList.contains('neonfront-p2p-portal-left-nav')) { 1845 leftBar.style.bottom = varyHeight + 'px' 1846 leftBar.style.height = (clientHeight - varyHeight) + 'px' 1847 } else { 1848 leftBar.style.bottom = '0px' 1849 leftBar.style.height = clientHeight + 'px' 1850 } 1851 rightContent.style.minHeight = (clientHeight - varyHeight) + 'px' 1852 leftBar.style.overflow = 'hidden auto' 1853 } else { 1854 // footer hide 1855 leftBar.style.height = clientHeight + 'px' 1856 leftBar.style.bottom = '' 1857 rightContent.style.minHeight = clientHeight + 'px' 1858 leftBar.style.overflow = 'hidden auto' 1859 } 1860 if (leftBar.style.position !== 'fixed') { 1861 const leftBarWidth = leftBar.offsetWidth || 260 1862 leftBar.style.position = 'fixed' 1863 leftBar.style.top = '0' 1864 leftBar.style.width = leftBarWidth + 'px' 1865 flexRow.style.paddingLeft = leftBarWidth + 'px' 1866 rightContent.style.marginLeft = '' 1867 } 1868 leftBar.style.left = flexRow.getBoundingClientRect().left + 'px' 1869 try { 1870 fixedTitle.style.display = '' 1871 } catch (e) { 1872 } 1873 } 1874 if (content.getBoundingClientRect().top > 0) { 1875 //roll back 1876 leftBar.style.position = 'static' 1877 leftBar.style.top = '' 1878 leftBar.style.bottom = '' 1879 leftBar.style.left = '' 1880 leftBar.style.width = '' 1881 flexRow.style.paddingLeft = '' 1882 rightContent.style.marginLeft = '' 1883 leftBar.style.minHeight = '' 1884 rightContent.style.minHeight = '0' 1885 try { 1886 fixedTitle.style.display = 'none' 1887 } catch (e) { 1888 } 1889 } 1890 } else { 1891 //roll back 1892 leftBar.style.position = 'static' 1893 leftBar.style.top = '' 1894 leftBar.style.bottom = '' 1895 leftBar.style.left = '' 1896 leftBar.style.width = '' 1897 flexRow.style.paddingLeft = '' 1898 rightContent.style.marginLeft = '' 1899 leftBar.style.minHeight = '' 1900 rightContent.style.minHeight = '0' 1901 try { 1902 fixedTitle.style.display = 'none' 1903 } catch (e) { 1904 } 1905 } 1906 } 1907 const preFix = setSliderBar(function() { 1908 fixSliderBar(); 1909 }, 4); 1910 try { 1911 const leftBar = document.getElementById("left-nav") 1912 leftBar.style.maxHeight = window.innerHeight + 'px' 1913 leftBar.style.overflow = 'hidden auto' 1914 window.addEventListener('scroll',preFix) 1915 window.addEventListener('resize',preFix) 1916 } catch (ignore) { 1917 //without sidebar not need fix 1918 } 1919</script>
1919 1920 1921 1922 1923</body> 1924</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.