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/franciscanworks/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, #F9FAFC); 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, 50%); 66 position: fixed; 67 z-index: 1; 68 } 69 .neonfront_element .form-check-input:checked { 70 background-color: var(--out-line-calibration-color, #F68E1E)!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, Arial,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, #F68E1E)!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, #F68E1E)!important; 101 border-color: #D9DFE3; 102 box-shadow: none !important; 103 } 104 105 .neonfront-btn-link { 106 color: var(--out-line-calibration-color, #F68E1E)!important; 107 } 108 .neonfront_stepper.on,.neonfront_stepper_num { 109 background: var(--theme-color, #F68E1E)!important; 110 } 111 112 .neonfront_payment_tab .active { 113 border-bottom: 4px solid var(--out-line-calibration-color, #F68E1E) !important; 114 color: var(--out-line-calibration-color, #F68E1E) !important; 115 } 116 117 .neonfront-btn-primary, .btn-primary { 118 background-color: var(--theme-color, #F68E1E) !important; 119 color: var(--primary-btn-text-color, #ffffff) !important; 120 border-color: var(--theme-color, #F68E1E) !important; 121 box-shadow: none !important; 122 } 123 .secondary-exit-btn { 124 color: var(--theme-color, #F68E1E) !important; 125 background-color: #FFF !important; 126 border: 1px solid var(--theme-color, #F68E1E) !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, #F68E1E) !important; 136 } 137 138 .neonfront-btn-outline-primary { 139 color: var(--out-line-calibration-color, #F68E1E)!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, #F68E1E) !important; 144 border-color: var(--theme-color, #F68E1E) !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, #F68E1E) !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, #222222)!important; 167 background-color: var(--footer-bg-color, #FFFFFF)!important; 168 padding-left: 0px; 169 padding-right: 0px; 170 } 171 .neonfront_footer_lv_info { 172 color: var(--footer-text-color, #222222)!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, #222222); 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, #222222)!important; 205 } 206 207 .neonfront-switch input:checked{ 208 background-color: var(--theme-color, #F68E1E) !important; 209 } 210 211 .popal-opportunities-tile .popal-opportunities-tile-col .pot-neon-round-img { 212 background-color: var(--theme-color, #F68E1E) !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, #F68E1E) !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: 8, 692 logo: "https:\/\/franciscanworks.app.neoncrm.com\/np\/clients\/franciscanworks\/logo.gif", 693 logoAlt: null, 694 logoWidth: 100, 695 logoUrl: null, 696 footerColumns: 2, 697 footerCol1Text: null, 698 footerCol2Text: null, 699 footerCol3Text: null, 700 displaySocialLink: true, 701 socialLinkIconAlign: "R", 702 socialLinkIconStyle: "D", 703 styles: {"headerBgColor":"#FFFFFF","headerTextColor":"#222222","pageFont":"Arial,sans-serif","pageBgColor":"#F9FAFC","pageBgMirror":"","pageBgImage":null,"themeJSSnippets":"","pageBgImageAlt":"","themeColor":"#F68E1E","footerBgColor":"#FFFFFF","pageBgAlign":"","pageFontColor":"#002D41","footerTextColor":"#222222","primaryBtnTextColor":"#ffffff","actBtnTextColor":"#222222"}, 704 socialLinks: [{"createBy":"Organization Brand Reminder Schedule","createTime":"2026-05-10T07:10:25.000-05:00","lastModifyBy":"Organization Brand Reminder Schedule","lastModifyTime":"2026-05-10T07:10:25.000-05:00","id":351,"templateId":8,"icon":"Facebook","url":"https:\/\/www.facebook.com\/FranciscanWorks"},{"createBy":"Organization Brand Reminder Schedule","createTime":"2026-05-10T07:10:25.000-05:00","lastModifyBy":"Organization Brand Reminder Schedule","lastModifyTime":"2026-05-10T07:10:25.000-05:00","id":352,"templateId":8,"icon":"Twitter","url":"https:\/\/www.twitter.com\/FranciscanWorks"}], 705 naviLinks: [{"createBy":"Organization Brand Reminder Schedule","createTime":"2026-05-10T07:10:25.000-05:00","lastModifyBy":"Organization Brand Reminder Schedule","lastModifyTime":"2026-05-10T07:10:25.000-05:00","id":277,"templateId":8,"url":"https:\/\/www.franciscanworks.org","name":"HOME","openInNewTab":1}], 706 _homePageURL: "https:\/\/www.franciscanworks.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 800 <div class="col-md-12 neonfront_element mt-0"> 801 <div id="globalError" class="row mt-3 neonfront-portal neonfront_form_failed_container" v-show="globalError"> 802 <div class="col-2">
803 <span class="fa fa-exclamation-circle mt-1" style="font-size: 2.25rem;"></span> 804 </div> 805 <div class="col-10"> 806 <h5 class="fs-6 mb-1" style="line-height: 42px">{{globalError}}</h5> 807 </div> 808 </div> 809 </div> 810 <div class="neonfront_element col-md-12"> 811 <label for="loginName" class="form-label">Username or Email</label> 812 <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"> 813 <div class="invalid-feedback"> 814 <div><i class="fa fa-exclamation-triangle"></i> 815 Username or Email is required. 816 </div> 817 </div> 818 </div> 819 <div class="neonfront_element col-md-12 login-password-field"> 820 <label for="password" class="form-label">Password</label> 821 <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"> 822 <i class="fas fa-eye-slash presentation" v-if="!showPassword" @click="showPsd(true)"></i> 823 <i class="fas fa-eye presentation" v-if="showPassword" @click="showPsd(false)"></i> 824 <div class="invalid-feedback"> 825 <div><i class="fa fa-exclamation-triangle"></i>Password is required.</div> 826 </div> 827 </div> 828 <div class="neonfront_element col-md-12 login-additional"> 829 <div class="form-check login-remember-me"> 830 <input class="form-check-input neonfront_checkbox" type="checkbox" value="yes" id="persistCookie" v-model="persistCookie"> 831 <label class="form-check-label neonfront_checkbox_label" for="persistCookie"> 832 Remember me for 2 weeks 833 </label> 834 </div> 835 <div class="trouble-login"> 836 <a href="/requestPassword" data-testid="link-forgot-password">Having trouble logging in?</a> 837 838 </div> 839 </div> 840 <div class="col-md-12 neonfront_element"> 841 <div class="row g-2 justify-content-center"> 842 <div class="col"> 843 <button type="button" class="btn neonfront-btn-primary btn-lg" @click="login" v-show="!loading" data-testid="bt
843n-login">Login</button> 844 <button class="btn neonfront-btn-primary btn-lg" type="button" disabled v-show="loading"> 845 Processing <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 846 </button> 847 </div> 848 </div> 849 </div> 850 <div class="col-md-12 neonfront_element login-separate"> 851 <div class="separate-line"></div> 852 <div class="separate-text">or</div> 853 <div class="separate-line"></div> 854 </div> 855 856 <div class="col-md-12 neonfront_element"> 857 <div class="create-account"> 858 Don't have an account? 859 <a v-if="activeTab === 0 || autoMergeOn" href="/forms/createaccount">Create an account</a> 860 <a v-else href="javascript:void(0)" @click="createFundraiser">Create an account</a> 861 </div> 862 </div> 863 864 </div> 865 </div> 866 </div> 867 </div> 868</div> 869<div class="modal fade neonfront-modal landing-page-login-modal" aria-hidden="true" id="fundraiserLoginModal" ref="createP2pAcctModal" data-bs-backdrop="static" tabindex="-1"> 870 <div class="modal-dialog" style="max-width: 580px;"> 871 <div class="modal-content px-sm-4 px-1"> 872 <div class="modal-header"> 873 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 874 </div> 875 876 <div class="modal-body" style="padding-top:0;padding-bottom:0"> 877 <div class="row mt-1"> 878 <div class="col login-body-title p2p-login-body-title"> 879 Create an Account 880 </div> 881 </div> 882 <div class="row mt-1"> 883 <div class="login-body-col"> 884 <div class="body-line" style="display: flex"> 885 <span> 886 <label for="firstName" class="input-label">First Name *</label> 887 <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)" /> 888 <div v-if="acctRules.fname.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.fname.errMsg}}</div> 889 </span> 890 <span style="margin-left: 30px;"> 891 <label for="lastName" class="input-label">Last Name *</label> 892 <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)" /> 893 <div v-if="acctRules.lname.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.lname.errMsg}}</div> 894 </span> 895 </div> 896 <div class="body-line"> 897 <label for="emailAddress" class="input-label" >Email Address *</label> 898 <input type="text" v-model="acctData.email" class="form-control" id="emailAddress" name="emailAddress" :class="{'invalid': acctRules.email.invalid}" @blur="checkAcctFieldVal($event, acctRules.email)" /> 899 <div v-if="acctRules.email.invalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{acctRules.email.errMsg}}</div> 900 </div> 901 <div class="body-line"> 902 <label for="createPassword" class="input-label">Create Password *</label> 903 <input type="password" v-model="acctData.password" class="form-control" id="createPassword" name="createPassword" :class="{'invalid': acctRules.psd1.invalid}" @blur="checkAcctFieldVal($event, acctRules.psd1)"/>
904 <span> 905 <i class="fa fa-info-circle"></i> 906 <span class="info-message-text">Enter at least 8 characters, including at least one number. Spaces not allowed.</span> 907 </span> 908 <i class="fas fa-eye-slash presentation1" v-if="!showCreatePassword" @click="showCreatePsd(true)"></i> 909 <i class="fas fa-eye presentation1" v-if="showCreatePassword" @click="showCreatePsd(false)"></i> 910 <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> 911 </div> 912 <div class="body-line" style="margin-top: -20px;margin-bottom: 0px !important;"> 913 <label for="confirmPassword" class="input-label">Confirm Password *</label> 914 <input type="password" class="form-control" id="confirmPassword" name="confirmPassword" :class="{'invalid': acctRules.psd2.invalid}" @blur="checkAcctFieldVal($event, acctRules.psd2)"/> 915 <i class="fas fa-eye-slash presentation2" v-if="!showConfirmPassword" @click="showConfirmPsd(true)"></i> 916 <i class="fas fa-eye presentation2" v-if="showConfirmPassword" @click="showConfirmPsd(false)"></i> 917 <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> 918 </div> 919 920 <div v-if="gdprSettings.profileEnabled || gdprSettings.statementEnabled" class="body-line"> 921 <label class="input-label">Data Privacy & Consent</label> 922 <div class="gdpr-setting-section"> 923 <div class="gdpr-setting-items"> 924 <div v-if="gdprSettings.email" class="gdpr-setting-item neonfront_element"> 925 <div class="checkbox-column"> 926 <input v-model="gdprValues.email" type="checkbox" id="gdpr.email" name="gdpr.email" class="form-check-input neonfront_checkbox"/> 927 </div> 928 <label for="gdpr.email" class="setting-item-label">{{gdprSettings.email}}</label> 929 </div> 930 <div v-if="gdprSettings.phone" class="gdpr-setting-item neonfront_element"> 931 <div class="checkbox-column"> 932 <input v-model="gdprValues.phone" type="checkbox" id="gdpr.phone" name="gdpr.phone" class="form-check-input neonfront_checkbox"/> 933 </div> 934 <label for="gdpr.email" class="setting-item-label">{{gdprSettings.phone}}</label> 935 </div> 936 <div v-if="gdprSettings.mail" class="gdpr-setting-item neonfront_element"> 937 <div class="checkbox-column"> 938 <input v-model="gdprValues.mail" type="checkbox" id="gdpr.mail" name="gdpr.mail" class="form-check-input neonfront_checkbox"/> 939 </div> 940 <label for="gdpr.mail" class="setting-item-label">{{gdprSettings.mail}}</label> 941 </div> 942 <div v-if="gdprSettings.sms" class="gdpr-setting-item neonfront_element"> 943 <div class="checkbox-column"> 944 <input v-model="gdprValues.sms" type="checkbox" id="gdpr.sms" name="gdpr.sms" class="form-check-input neonfront_checkbox"/> 945 </div> 946 <label for="gdpr.sms" class="setting-item-label">{{gdprSettings.sms}}</label> 947 </div> 948 <div v-show="gdprValues.sms" class="smsPhoneNum-section" style="padding-left:25px"> 949 <label for="smsPhoneNum" class="input-label">What's the best number for us to text you? *</label> 950 <input v-model="gdprValues.smsPhoneNum" type="text" class="form-control" id="smsPhoneNum" name="smsPhoneNum" :class="{'invalid': gdprValues.smsPhoneInvalid}" @blur="checkGdprSmsPhoneNum($event)"/> 951 <div v-if="gdprValues.smsPhoneInvalid" class="field-err-msg"><i class="fa fa-exclamation-triangle"></i>{{gdprValues.smsPhoneInvalidMsg}}</div> 952 </div> 953 <div v-if="gdprSettings.share" class="gdpr-setting-item neonfront_element"> 954 <div class="checkbox-column"> 955 <input v-model="gdprValues.share" type="checkbox" id="gdpr.share" name="gdpr.share" class="form-check-input neonfront_checkbox"/> 956 </div> 957 <label for="gdpr.share" class="setting-item-label">{{gdprSettings.share}}</label> 958 </div> 959 </div> 960 961 <div v-if="gdprSettings.statement" class="gdpr-statement"> 962 {{gdprSettings.statement}} 963 </div> 964 <div v-if="gdprSettings.policyUrl" class="gdpr-policy"> 965 <a :href="gdprSettings.policyUrl" target="_blank" style="text-decoration: none">{{gdprSettings.policyLabel}}</a> 966 </div> 967 </div> 968 </div> 969 </div> 970 </div> 971 </div> 972 <div class="login-footer p2p-login-footer"> 973 <button v-if="!doCreateAcct" type="button" 974 class="btn neonfront-btn-primary btn-lg p2p-btn" 975 :disabled="checkCreateAcctField" 976 @click="doP2pCreateAccount">Submit</button> 977 <button v-if="doCreateAcct" class="btn neonfront-btn-primary btn-lg p2p-btn" type="button" disabled> 978 Processing <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 979 </button> 980 <div class="col-md-12 neonfront_element login-separate p2p_login_separate"> 981 <div class="separate-line"></div> 982 <div class="separate-text">or</div> 983 <div class="separate-line"></div> 984 </div> 985 <div class="go_login_sty">Have an account? <a href="javascript:void(0)" data-bs-dismiss="modal">Log in</a></div> 986 </div> 987 </div> 988 </div> 989</div> 990 991</body> 992</html> 993 994 </div> 995 </div> 996 </div> 997 </div> 998 </div> 999 </div> 1000 <!DOCTYPE html> 1001<html> 1002<body> 1003 <div class="container-fluid neonfront_footer" id="footer-content"> 1004 <div class="row neonfront_footer_lv_info"> 1005 <div v-if="theme.footerColumns==1" class="col-md-12" style="padding-left:30px;padding-right:30px;"> 1006 <div v-html="theme.footerCol1Text"></div> 1007 </div> 1008 <div v-if="theme.footerColumns==2" class="col-md-6" style="padding-left:30px;"> 1009 <div class="float-md-start float-none" v-html="theme.footerCol1Text"></div> 1010 </div> 1011 <div v-if="theme.footerColumns==2" class="col-md-6" style="padding-right:30px;"> 1012 <div class="float-md-end float-none" v-html="theme.footerCol2Text"></div> 1013 </div> 1014 <div v-if="theme.footerColumns==3" class="col-md-4" style="padding-left:30px;"> 1015 <div class="float-md-start float-none" v-html="theme.footerCol1Text"></div> 1016 </div> 1017 <div v-if="theme.footerColumns==3" class="col-md-4 text-md-center footer_center_column"> 1018 <div class="footer_center_column_content" style="margin:0 auto;" v-html="theme.footerCol2Text"></div> 1019 </div> 1020 <div v-if="theme.footerColumns==3" class="col-md-4" style="padding-right:30px;"> 1021 <div class="float-md-end float-none" v-html="theme.footerCol3Text"></div> 1022 </div> 1023 </div> 1024 <div v-if="theme.displaySocialLink" 1025 :class="['neonfront_footer_lv_media', 1026 theme.socialLinkIconAlign==='C' ? 'text-center' : (theme.socialLinkIconAlign==='R' ? 'text-end' : 'text-start'), 1027 theme.socialLinkIconStyle==='L' ? 'text-white' : 'text-dark']"> 1028 <template v-for="item in (theme.socialLinks||[])" :key="item.icon"> 1029 <a v-if="item.url" 1030 :href="item.icon==='Email' ? 'mailto:'+item.url : (item.url.startsWith('http://') || item.url.startsWith('https://') || item.url.startsWith('//') ? item.url : 'https://'+item.url)" 1031 :style="theme._previewMode ? {'pointer-events': 'none'} : {}" 1032 target="_blank" 1033 class="text-reset social-link-icon"> 1034 <img width="24" height="24" 1035 :src="getSocialMediaIcon(item.icon, theme.socialLinkIconStyle)"> 1036 </a> 1037 </template> 1038 </div> 1039 1040 <div class="footer-root"> 1041 <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> 1042 <div class="footer-root-right"> 1043 <a href="https://neonone.com/" target="_blank"> 1044 <div class="footer-root-right-header"><img width="60" height="20" src="/nx/portal-static/img/logo-variations.svg"/></div> 1045 <div class="footer-root-right-footer"><img width="60" height="20" src="/nx/portal-static/img/merchant-copy.svg"/></div> 1046 </a> 1047 </div> 1048 </div> 1049 </div> 1050</body> 1051</html> 1052 </div> 1053 1054 1055 <!DOCTYPE html> 1056<html lang="en"> 1057<body> 1058 <!DOCTYPE html> 1059<html lang="en"> 1060<body> 1061<!-- Modal --> 1062<div class="modal fade neonfront-modal neonfront-confirm-modal" id="confirmSubMembershipEndModal" data-bs-backdrop="static" tabindex="-1"> 1063 <div class="modal-dialog" style="max-width: 580px;"> 1064 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1065 <div class="modal-header"> 1066 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelSubMembershipEndTurnOff"></button> 1067 </div> 1068 <div class="modal-body"> 1069 <div class="row mt-1"> 1070 <div class="col"> 1071 <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> 1072 </div> 1073 </div> 1074 </div> 1075 <div class="modal-footer"> 1076 <button type="button" class="btn btn-link neonfront-btn-l
1076ink" @click="cancelSubMembershipEndTurnOff" style="width: auto">Cancel</button> 1077 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmSubMembershipEndTurnOff" style="width: auto">Confirm</button> 1078 </div> 1079 </div> 1080 </div> 1081</div> 1082</body> 1083</html> 1084 <!DOCTYPE html> 1085<html lang="en"> 1086<body> 1087<!-- Modal --> 1088<div class="modal fade neonfront-modal neonfront-confirm-modal" id="addressListDeleteModal" data-bs-backdrop="static" tabindex="-1"> 1089 <div class="modal-dialog" style="max-width: 580px;"> 1090 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1091 <div class="modal-header"> 1092 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelAddressListDeleteModal"></button> 1093 </div> 1094 <div class="modal-body"> 1095 <div class="row mt-1"> 1096 <div class="col"> 1097 <p>Are you sure you want to delete this address?</p> 1098 <p class="desc">Your address will be deleted.</p> 1099 </div> 1100 </div> 1101 </div> 1102 <div class="modal-footer"> 1103 <button type="button" class="btn btn-link neonfront-btn-link" @click="cancelAddressListDeleteModal" style="width: auto">Cancel</button> 1104 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmAddressListDeleteModal" style="width: auto">Confirm</button> 1105 </div> 1106 </div> 1107 </div> 1108</div> 1109</body> 1110</html> 1111 <!DOCTYPE html> 1112<html lang="en"> 1113<body> 1114<!-- Modal --> 1115<div class="modal fade neonfront-modal neonfront-confirm-modal" id="addressListCommonDeleteModal" data-bs-backdrop="static" tabindex="-1"> 1116 <div class="modal-dialog" style="max-width: 580px;"> 1117 <div class="modal-content px-sm-4 px-1" style="z-index: 20000;"> 1118 <div class="modal-header"> 1119 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="cancelAddressListDeleteModal"></button> 1120 </div> 1121 <div class="modal-body"> 1122 <div class="row mt-1"> 1123 <div class="col"> 1124 <p>Address cannot be deleted because of the following linked data:</p> 1125 <p class="desc" v-for="item in deleteInfo"> 1126 {{decisionDeleteInfo(item)}} 1127 </p> 1128 </div> 1129 </div> 1130 </div> 1131 <div class="modal-footer"> 1132 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="cancelAddressListCommonDeleteModal" style="width: auto;margin-left: auto">Close</button> 1133 </div> 1134 </div> 1135 </div> 1136</div> 1137</body> 1138</html> 1139</body> 1140</html> 1141 1142 <div class="modal fade neonfront-modal" id="goP2pConfirmModal" data-bs-backdrop="static" tabindex="-1"> 1143 <div class="modal-dialog"> 1144 <div class="modal-content px-sm-4 px-1 go-p2p-confirm-modal"> 1145 <div class="header"> 1146 Leaving this Page 1147 </div> 1148 <div class="content"> 1149 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. 1150 <br/><br/>Do you want to continue? 1151 </div> 1152 <div class="footer"> 1153 <button type="button" class="btn btn-link neonfront-btn-link" @click="cancelP2pConfirmModal()" 1154 style="width: auto; font-family: var(--page-font, Lato)">Cancel 1155 </button> 1156 <button type="button" class="btn neonfront-btn-primary btn-lg px-4" @click="confirmP2pConfirmModal" 1157 style="width: auto; font-family: var(--page-font, Lato)">Continue 1158 </button> 1159 </div> 1160 <i class="fa-solid fa-xmark-large close_icon" @click="cancelP2pConfirmModal"></i> 1161 </div> 1162 </div> 1163</div> 1164 1165</div> 1166
1167<script src="/nx/portal-static/component/vue/vue-3.1.2.min.js"></script>
vendor: 1 bytes, line 1167
1167
1168<script src="/nx/portal-static/component/axios/axios.min.js"></script>
vendor: 1 bytes, line 1168
1168
1169<script src="/nx/portal-static/component/qs/qs.min.js"></script>
vendor: 1 bytes, line 1169
1169
1170<script src="/nx/portal-static/component/bootstrap/js/bootstrap.bundle.min.js"></script>
vendor: 1 bytes, line 1170
1170
1171<script src="/nx/portal-static/component/laydate/laydate.js"></script>
vendor: 1 bytes, line 1171
1171
1172<script src="/nx/portal-static/component/cropperjs/cropper.min.js"></script>
vendor: 1 bytes, line 1172
1172
1173<script src="/nx/portal-static/component/moment-js/moment-2.30.1.min.js"></script>
vendor: 1 bytes, line 1173
1173
1174<script src="/nx/portal-static/component/moment-js/moment-timezone.min.js"></script>
1174 1175
1176<script src="/nx/portal-static/js/portal.all.js"></script>
1176 1177<!-- 1178<th:block th:if="${churnZeroEnabled && !#strings.isEmpty(churnZeroAccountExternalId)}">
1179<script src="https://neonone.us1app.churnzero.net/churnzero.js"></script>
vendor: 1 bytes, line 1179
1179
1180<script type="application/javascript"> 1181 var ChurnZero = ChurnZero || [] 1182 1183 ChurnZero.push(['setAppKey', '1!MFdwDlKbVUgVpSRtljcqdO9tOYWtqDKqGG7trJX5JYwtE02']) // AppKey from ChurnZero 1184 ChurnZero.push(['setContact', '', '']) 1185</script>
1185 1186</th:block> 1187--> 1188
1189<script type="application/javascript"> 1190 // Common JS Code 1191</script>
1191 1192 1193 1194 1195
1196<script> 1197 // CLP embed: notify parent on DOMContentLoaded for re-postMessage 1198 (function () { 1199 const urlParams = new URLSearchParams(window.location.search); 1200 const clpEmbedEnv = sessionStorage.getItem('clpEmbedEnv') === '1' 1201 || urlParams.get('clpEmbedEnv') === '1'; 1202 if (!clpEmbedEnv) return; 1203 const embedIframeId = urlParams.get('embedIframeId') || sessionStorage.getItem('clpEmbedIframeId'); 1204 const embedIframeDomainUrl = urlParams.get('embedIframeDomainUrl') || sessionStorage.getItem('clpEmbedDomainUrl'); 1205 if (!embedIframeId || !embedIframeDomainUrl) return; 1206 window.addEventListener('DOMContentLoaded', function () { 1207 parent.postMessage({type: 'DOMContentLoaded', embedIframeId: embedIframeId}, embedIframeDomainUrl); 1208 }); 1209 }()); 1210</script>
1210 1211
1212<script src="/nx/portal-static/js/clp-embed-content.js"></script>
vendor: 66 bytes, lines 1212-1215
1212 1213 1214 1215<script async src="https://www.googletagmanager.com/gtag/js?id=
1215G-E5PVK7VDYC
vendor: 12 bytes, line 1215
1215"></script>
1216<script> 1217
vendor: 139 bytes, lines 1217-1220
1217window.dataLayer = window.dataLayer || []; 1218 function gtag(){dataLayer.push(arguments);} 1219 gtag('js', new Date()); 1220 gtag('config', '
1220G-E5PVK7VDYC
vendor: 4 bytes, line 1220
1220');
1221</script>
vendor: 72 bytes, lines 1221-1224
1221 1222 1223 1224 <script src="https://www.google.com/recaptcha/enterprise.js?render=
12246Lciqi8rAAAAAG87Wg7usbkvyHVTXylFPgeSyHkM
vendor: 24 bytes, line 1224
1224" async defer></script>
1225<script type="text/javascript"> 1226 const appData = { 1227 showCreatePassword: false, 1228 showConfirmPassword: false, 1229 doLoginLoading: false, 1230 doCreateAcct: false, 1231 acctRules: { 1232 fname: {type: 'name', invalid: null, errMsg: 'First Name is required.'}, 1233 lname: {type: 'name', invalid: null, errMsg: 'Last Name is required.'}, 1234 email: {type: 'email', invalid: null, errMsg: 'Email Address is required.'}, 1235 psd1: {type: 'psd1', invalid: null, errMsg: 'Create Password is required.'}, 1236 psd2: {type: 'psd2', invalid: null, errMsg: 'Confirm Password is required.'} 1237 }, 1238 acctData: { 1239 firstName: '', 1240 lastName: '', 1241 email: '', 1242 password: '' 1243 }, 1244 gdprSettings: {}, 1245 autoMergeOn: false, 1246 gdprValues: { 1247 email: false, 1248 phone: false, 1249 mail: false, 1250 sms: false, 1251 share: false, 1252 smsPhoneNum: '', 1253 smsPhoneInvalid: null, 1254 smsPhoneInvalidMsg: '' 1255 }, 1256 loginName: '', 1257 password: '', 1258 persistCookie: '', 1259 loading: false, 1260 loginNameError: false, 1261 passwordError: false, 1262 globalError: '', 1263 showPassword: false, 1264 source: '', 1265 // OAuth Authorization Server handoff: literal "as" == OauthConstant.LOGIN_SOURCE / LoginSourceConstants.OAUTH_AS 1266 targetUrl:'', 1267 redirectUrl: '', 1268 fromNeonWebSite: false, 1269 embeddedLogin: false, 1270 activeTab: 0, 1271 googleReCaptchaEnabled: true, 1272 googleReCaptchaEnabled0: true, 1273 enableModernLogin: false, 1274 fromLogout: false, 1275 recaptchaResponse: null 1276 } 1277 1278 const appMethods = { 1279 tabChange(index){ 1280 this.activeTab = index 1281 }, 1282 doLogin: function () { 1283 if (this.enableModernLogin) { 1284 if (this.embeddedLogin || this.source === 'embedded') { 1285 const loginName = btoa(this.loginName) 1286 const loginPassword = btoa(this.password) 1287 const url = '/nx/auth/authenticate?source=embedded' 1288 + '&loginName=' + encodeURIComponent(loginName) 1289 + '&loginPassword=' + encodeURIComponent(loginPassword) 1290 + (this.persistCookie === true ? '&rememberMe=true' : '') 1291 window.location.href = url 1292 return 1293 } 1294 // Align with legacy signIn.do: password login does not submit/verify reCAPTCHA. 1295 this.loading = true 1296 this.globalError = '' 1297 // Modern resolves the post-login redirect server-side, so the active tab has to 1298 // travel with the request (the legacy branch below picks /p2p/overview locally). 1299 // source=as owns targetUrl â ai= is appended to it â so never overwrite it there. 1300 let target = this.targetUrl || this.redirectUrl || '' 1301 if (!target && !this.source && this.activeTab === 1) { 1302 target = '/p2p/overview' 1303 } 1304 let url = '/nx/auth/authenticate?targetUrl=' + encodeURIComponent(target); 1305 if (this.source) { 1306 url += '&source=' + encodeURIComponent(this.source); 1307 } 1308 axios.post(url, { 1309 loginName: this.loginName, 1310 password: this.password, 1311 rememberMe: this.persistCookie === true, 1312 requestId: '04528c8e-3ab3-463d-9429-1dd412be25a9', 1313 source: this.source || '' 1314 }).then((res) => { 1315 const body = res.data || {}; 1316 if (body.success && body.data) { 1317 window.location = body.data.redirect; 1318 } else { 1319 this.loading = false 1320 const msgs = body.messages || []; 1321 this.globalError = (msgs[0] && msgs[0].message) || 'Login Name/Password is invali
1321d'; 1322 } 1323 }).catch(() => { 1324 this.loading = false 1325 this.globalError = 'Login Name/Password is invalid'; 1326 }); 1327 return 1328 } 1329 let $loginData = { 1330 loginName: this.loginName, 1331 loginPassword: this.password, 1332 persistCookie: this.persistCookie === true ? 'yes' : this.persistCookie, 1333 ajaxLogin: true, 1334 source: this.fromNeonWebSite? 'duda' : this.source, 1335 targetUrl: this.targetUrl || this.redirectUrl, 1336 requestId: '04528c8e-3ab3-463d-9429-1dd412be25a9' 1337 } 1338 this.loading = true 1339 this.globalError = '' 1340 axios.post('/np/security/signIn.do', Qs.stringify($loginData)).then(response => { 1341 let $data = response.data 1342 if ($data.status === 'success') { 1343 if (this.loginName === 'admin') { 1344 window.location = '/np/admin/content/contentList.do' 1345 } else if ($data.succeedRedirectPath) { 1346 window.location = $data.succeedRedirectPath 1347 } else if(this.activeTab === 1) { 1348 window.location = '/p2p/overview' 1349 } else { 1350 window.location = '/constituent/dashboard' 1351 } 1352 } else { 1353 this.loading = false 1354 this.globalError = $data.errors[0] 1355 } 1356 }) 1357 }, 1358 login: function () { 1359 let validatePass = true 1360 if (Validator.required.check(this.loginName)) { 1361 this.loginNameError = true 1362 validatePass = false 1363 } 1364 if (Validator.required.check(this.password)) { 1365 this.passwordError = true 1366 validatePass = false 1367 } 1368 if (!validatePass) { 1369 return 1370 } 1371 this.passwordError = false 1372 this.loginNameError = false 1373 this.doLogin() 1374 }, 1375 1376 showPsd: function ($show) { 1377 if ($show) { 1378 this.showPassword = true 1379 document.querySelector('#password').type = 'text' 1380 } else { 1381 this.showPassword = false 1382 document.querySelector('#password').type = 'password' 1383 } 1384 }, 1385 fn_openAuthWin: function (src) { 1386 if (this.enableModernLogin) { 1387 // Same sources as password login (targetUrl / redirectUrl), plus live ?redirect= 1388 // from the address bar â Thymeleaf injection alone has been unreliable for social. 1389 const params = new URLSearchParams(window.location.search || ''); 1390 let path = (params.get('redirect') 1391 || params.get('target') 1392 || this.targetUrl 1393 || this.redirectUrl 1394 || '').trim(); 1395 if (path) { 1396 try { 1397 path = decodeURIComponent(path); 1398 } catch (e) { /* keep raw */ } 1399 } 1400 if (!path) { 1401 path = window.location.pathname + window.location.search; 1402 const pathOnly = (window.location.pathname || '').replace(/\/+$/, '') || '/'; 1403 if (pathOnly === '/login' || pathOnly === '/nx/login' || /\/login$/.test(pathOnly)) { 1404 path = '/'; 1405 } 1406 } 1407 neonSocialLogin(src, { 1408 targetUrl: path, 1409 orgId: this.orgId, 1410 // Literal "as" == OauthConstant.LOGIN_SOURCE / LoginSourceConstants.OAUTH_AS 1411 custom: this.source === 'as' ? 'as' : undefined 1412 }); 1413 return; 1414 } 1415 const path = "/np/clients/" + this.orgId + "/snOpenAuthWin.do?"; 1416 const param = "src=" + src + "&da=login"+ (this.fromNeonWebSite?'&custom=duda':''); 1417 const url = path + param; 1418 const size = 'width=750,height=450,top=230,left=370,toolbar=no'; 1419 window.location.href = url; 1420 }, 1421 enterClick: function (e) { 1422 if (e.keyCode === 13) { 1423 if (e.target.closest('.neonfront_input')) { 1424 this.login() 1425 } 1426 if (e.target.closest('.form-check-input')) { 1427 this.login() 1428 } 1429 } 1430 }, 1431 listenEnterKey: function () { 1432 document.addEventListener('keydown', this.enterClick) 1433 }, 1434 createFundraiser: function () { 1435 this.doLoginLoading = false 1436 this.doCreateAcct = false 1437 this.p2pLoginErrorMessages = []
1438 this.acctRules.fname.invalid = null 1439 this.acctRules.lname.invalid = null 1440 this.acctRules.email.invalid = null 1441 this.acctRules.psd1.invalid = null 1442 this.acctRules.psd2.invalid = null 1443 this.$nextTick(() => { 1444 const modalElement = this.$refs.createP2pAcctModal; 1445 document.body.appendChild(modalElement); 1446 const modal = new bootstrap.Modal(this.$refs.createP2pAcctModal) 1447 modal.show() 1448 }) 1449 }, 1450 invisibleReCaptchaInit: function () { 1451 window.ReCaptchaLoaded = this.reCaptchaCallback; 1452 let tag = document.createElement("div") 1453 tag.className = 'g-recaptcha' 1454 document.body.appendChild(tag); 1455 let timer = setInterval(() => { 1456 if(window.grecaptcha && grecaptcha.enterprise && typeof window.grecaptcha.enterprise.render === 'function'){ 1457 window.grecaptcha.enterprise.render(tag,{ 1458 sitekey: '6Lciqi8rAAAAAG87Wg7usbkvyHVTXylFPgeSyHkM', 1459 size: 'invisible' 1460 }); 1461 clearInterval(timer); 1462 } 1463 },500); 1464 }, 1465 reCaptchaCallback: function ($token) { 1466 this.recaptchaResponse = $token 1467 if(window.grecaptcha && window.grecaptcha.enterprise) { 1468 window.grecaptcha.enterprise.reset() 1469 } 1470 this.doP2pCreateAccountSendToServer() 1471 }, 1472 validateReCaptcha:function () { 1473 if(window.grecaptcha && window.grecaptcha.enterprise) { 1474 this.recaptchaResponse = null 1475 window.grecaptcha.enterprise.execute().then(($token) => { 1476 this.reCaptchaCallback($token) 1477 }) 1478 } else { 1479 this.doP2pCreateAccountSendToServer() 1480 } 1481 }, 1482 doP2pCreateAccount: function () { 1483 this.doCreateAcct = true 1484 this.validateReCaptcha() 1485 }, 1486 doP2pCreateAccountSendToServer: function () { 1487 let formData = new FormData(); 1488 formData.append('firstName', this.acctData.firstName.trim()); 1489 formData.append('lastName', this.acctData.lastName.trim()); 1490 formData.append('email', this.acctData.email.trim()); 1491 formData.append('password', this.acctData.password.trim()); 1492 formData.append('recaptchaResponse', this.recaptchaResponse); 1493 if (this.gdprSettings.profileEnabled) { 1494 formData.append('gdpr.email', this.gdprValues.email); 1495 formData.append('gdpr.phone', this.gdprValues.phone); 1496 formData.append('gdpr.mail', this.gdprValues.mail); 1497 formData.append('gdpr.sms', this.gdprValues.sms); 1498 formData.append('gdpr.share', this.gdprValues.share); 1499 formData.append('gdpr.smsPhoneNum', this.gdprValues.smsPhoneNum); 1500 } 1501 axios.post('/nx/portal/p2p-data/create-account', formData, {}).then(response => { 1502 if (response.data.success) { 1503 this.doP2pLogin(this.acctData.email, this.acctData.password) 1504 } else { 1505 alert(response.data.messages[0].message); 1506 this.doCreateAcct = false 1507 } 1508 }).catch(error => { 1509 console.log(error) 1510 this.doCreateAcct = false 1511 alert('Create account failed, please try again.') 1512 }) 1513 }, 1514 doP2pLogin: function (name, password) { 1515 this.doLoginLoading = true 1516 if (this.enableModernLogin) { 1517 // Align with legacy: password login does not submit/verify reCAPTCHA. 1518 let url = '/nx/auth/authenticate?targetUrl=' + encodeURIComponent('/p2p/overview') 1519 axios.post(url, { 1520 loginName: name, 1521 password: password, 1522 requestId: '04528c8e-3ab3-463d-9429-1dd412be25a9' 1523 }).then((res) => { 1524 const body = res.data || {}; 1525 if (body.success && body.data) { 1526 window.location.href = body.data.redirect; 1527 } else { 1528 const msgs = body.messages || []; 1529 this.globalError = (msgs[0] && msgs[0].message) || 'Login failed'; 1530 alert(this.globalError) 1531 } 1532 this.doCreateAcct = false 1533 this.doLoginLoading = false 1534 }).catch((error) => { 1535 console.error(error.response) 1536 alert('Login error: ' + JSON.stringify(error.response)) 1537 this.doLoginLoading = false 1538 }) 1539 return 1540 } 1541 let params = { 1542 loginName: name, 1543 loginPassword: password, 1544 orgId: 'franciscanworks', 1545 ajaxLogin: true, 1546 requestId: '04528c8e-3ab3-463d-9429-1dd412be25a9' 1547 } 1548 axios.post('/np/security/encouragedSignIn.do', Qs.stringify(params)).then(response => { 1549 let result = response.data 1550 if (result.status === 'success') { 1551 window.location.href = 'https://' + window.location.host + '/p2p/overview' 1552 } else { 1553 alert('Login error: ' + JSON.stringify(result.errors)) 1554 } 1555 this.doCreateAcct = false 1556 this.doLoginLoading = false 1557 }).catch(error => { 1558 console.error(error.response) 1559 alert('Login error: ' + JSON.stringify(error.response)) 1560 this.doLoginLoading = false 1561 }) 1562 }, 1563 checkAcctFieldVal: function ($event, rule) { 1564 let val = $event.target.value.trim(); 1565 if (rule.type === 'name' && !val) {
1566 rule.invalid = true 1567 } else if (rule.type === 'email' && !val) { 1568 rule.errMsg = 'Email Address is required.' 1569 rule.invalid = true 1570 } else if (rule.type === 'email' && Validator['email'].check(val)) { 1571 rule.errMsg = 'Email Address format is invalid.' 1572 rule.invalid = true 1573 } else if (rule.type === 'psd1' && !val) { 1574 rule.errMsg = 'Create Password is required.' 1575 rule.invalid = true 1576 } else if (rule.type === 'psd1' && Validator.password.check(val)) { 1577 rule.errMsg = 'Your password requires at least 8 characters, including at least one number. Spaces are not allowed.' 1578 rule.invalid = true 1579 } else if (rule.type === 'psd2') { 1580 if (val) { 1581 let val1 = document.querySelector('#createPassword').value 1582 rule.errMsg = 'Confirm Password does not match.' 1583 rule.invalid = (val !== val1.trim()) 1584 } else { 1585 rule.errMsg = 'Confirm Password is required.' 1586 rule.invalid = true 1587 } 1588 } else { 1589 rule.invalid = false 1590 } 1591 }, 1592 showConfirmPsd: function ($show) { 1593 if ($show) { 1594 this.showConfirmPassword = true 1595 document.querySelector('#confirmPassword').type = 'text' 1596 } else { 1597 this.showConfirmPassword = false 1598 document.querySelector('#confirmPassword').type = 'password' 1599 } 1600 }, 1601 showCreatePsd: function ($show) { 1602 if ($show) { 1603 this.showCreatePassword = true 1604 document.querySelector('#createPassword').type = 'text' 1605 } else { 1606 this.showCreatePassword = false 1607 document.querySelector('#createPassword').type = 'password' 1608 } 1609 }, 1610 loadGdprSetting: function () { 1611 let previewMode = false 1612 if (previewMode) { 1613 return; 1614 } 1615 axios.get('/nx/portal/p2p-data/login-settings').then(response => { 1616 if (response.data.success) { 1617 this.gdprSettings = response.data.data.gdprSettings 1618 this.autoMergeOn = response.data.data.autoMergeOn 1619 } 1620 }).catch(error => { 1621 alert('Load GDPR settings failed, please try again.') 1622 }) 1623 }, 1624 checkGdprSmsPhoneNum: function ($event) { 1625 let val = $event.target.value.trim(); 1626 if (!val) { 1627 this.gdprValues.smsPhoneInvalid = true 1628 this.gdprValues.smsPhoneInvalidMsg = 'The SMS/MMS Number is required.' 1629 return 1630 } 1631 let usPhoneReg = /^(\+?1[-\s]?)?\(?[2-9]\d{2}\)?[-\s]?[2-9](?!11)\d{2}[-\s]?\d{4}$/ 1632 if (!usPhoneReg.test(val.replace(/\s+/g, ''))) { 1633 this.gdprValues.smsPhoneInvalid = true 1634 if (val.replace(/[\s\-()]/g, '').match(/^[^1]\d{10}$/)) { 1635 this.gdprValues.smsPhoneInvalidMsg = '11-digit numbers must begin with the country code 1 (US/Canada).' 1636 } else { 1637 this.gdprValues.smsPhoneInvalidMsg = 'Please enter a valid 10 or 11 digit mobile number.' 1638 } 1639 return 1640 } 1641 this.gdprValues.smsPhoneInvalid = false 1642 this.gdprValues.smsPhoneInvalidMsg = '' 1643 } 1644 } 1645 1646 const appComputed = { 1647 checkCreateAcctField: function () { 1648 return !(this.acctRules.fname.invalid === false && this.acctRules.lname.invalid === false 1649 && this.acctRules.email.invalid === false && this.acctRules.psd1.invalid === false 1650 && this.acctRules.psd2.invalid === false && (!this.gdprValues.sms || (this.gdprValues.smsPhoneNum && this.gdprValues.smsPhoneInvalid === false))) 1651 }, 1652 } 1653 1654 const appWatch = {} 1655 1656 const appConfig = { 1657 data: function () { 1658 return appData 1659 }, 1660 methods: appMethods, 1661 computed: appComputed, 1662 watch: appWatch, 1663 created: function() { 1664 const params = new URLSearchParams(window.location.search); 1665 const activeTab = params.get('activeTab'); 1666 if(activeTab === '1') { 1667 this.activeTab = 1 1668 } 1669 }, 1670 mounted: function () { 1671 if(this.googleReCaptchaEnabled || this.googleReCaptchaEnabled0) { 1672 this.invisibleReCaptchaInit() 1673 } 1674 this.listenEnterKey() 1675 this.loadGdprSetting() 1676 } 1677 } 1678</script>
1678 1679 1680 1681
1682<script type="application/javascript"> 1683 appData.loggedIn = false 1684 appData.previewMode = false 1685 appData.orgId = 'franciscanworks' 1686 appData.currentAccountId = 1687 appData.accountBasicInfo = '' 1688 appData.profilePhoto = { 1689 url: '', 1690 approved: false 1691 } 1692 appData.showMenu = false 1693 appData.formCurrency= '$' 1694 appData.formCurrencyCode= 'USD' 1695 appData.theme = window._neonThemeData || {} 1696 appMethods.formatAmount = function (amount) { 1697 return Formatter.numberFormat(amount, 2, this.formCurrency) 1698 } 1699 appMethods.showP2pConfirmModal = function() { 1700 bootstrap.Modal.getInstance(document.getElementById("goP2pConfirmModal")).show() 1701 } 1702 appMethods.cancelP2pConfirmModal = function(){ 1703 bootstrap.Modal.getInstance(document.getElementById("goP2pConfirmModal")).hide() 1704 } 1705 appMethods.confirmP2pConfirmModal = function(){ 1706 window.location.href='/p2p/overview' 1707 } 1708 appMethods.getSocialMediaIcon = function (name, style) { 1709 if (typeof getSocialIconURL === 'function') return getSocialIconURL(name, style) 1710 // legacy fallback 1711 return style === 'D' 1712 ? '/nx/static/img/icons/social-media/darkicons/' + name + '.svg' 1713 : '/nx/static/img/icons/social-media/lighticons/' + name + '.svg' 1714 } 1715 // Add interceptor for portal page 1716 axios.interceptors.request.use(function (config) { 1717 if(appData.previewMode){ 1718 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') 1719 } 1720 return config 1721 }, function (error) { 1722 // ... 1723 return Promise.reject(error) 1724 }); 1725 1726 (function (){ 1727 if(window.location.href.includes('/constituent')){ 1728 window.addEventListener( "pageshow", function ( $event ) { 1729 const performanceNavigationTiming = performance.getEntriesByType('navigation')[0]; 1730 // performanceNavigationTiming.type === 'back_forward' for firefox 1731 const historyTraversal = $event.persisted || performanceNavigationTiming.type === 'back_forward'; 1732 if ( historyTraversal ) { 1733 window.location.reload(); 1734 } 1735 }); 1736 } 1737 })(); 1738 const originalMounted = appConfig.mounted 1739 appConfig.mounted = function() { 1740 const result = originalMounted.apply(this); 1741 const $dom = document.getElementById("goP2pConfirmModal") 1742 if($dom) { 1743 new bootstrap.Modal($dom) 1744 } 1745 return result 1746 } 1747 appWatch.theme = { 1748 handler: function(newVal) { 1749 if (typeof applyThemeCSSVars === 'function') applyThemeCSSVars(newVal) 1750 }, 1751 deep: true 1752 } 1753 const vueApp = Vue.createApp(appConfig) 1754 vueApp.config.errorHandler = function (err, vm, info) { 1755 if (handleVueJSError) { 1756 handleVueJSError(err, vm, info) 1757 } 1758 console.log(err) 1759 } 1760 vueApp.component('neon-multiselect', window.NeonMultiselect) 1761 vueApp.component('neon-search-box', window.NeonSearchBox) 1762 vueApp.component('neon-fileupload', window.NeonFileupload) 1763 vueApp.component('neon-advancedsearch', window.NeonAdvancedsearch) 1764 vueApp.component('neon-select', window.NeonSelect) 1765 vueApp.component('neon-img-cutter', window.NeonImgCutter) 1766 vueApp.component('neon-pagination', window.NeonPagination) 1767 vueApp.component('neon-pagination-plus', window.NeonPaginationPlus) 1768 vueApp.component('neon-share-modal', window.NeonShareModal) 1769 vueApp.component('neon-search-select', window.NeonSearchSelect) 1770 vueApp.component('neon-search-location', window.NeonSearchLocation) 1771 vueApp.component('neon-input', window.NeonInput) 1772 const app = vueApp.mount('#app') 1773 window.__neonApp = app 1774</script>
1774 1775 1776 1777 1778
1778<script type="text/javascript"> 1779 function setSliderBar(func , wait , immediate) { 1780 let timeout 1781 return function () { 1782 let context = this, args = arguments 1783 let later = function() { 1784 timeout = null 1785 if (!immediate) func.apply(context, args) 1786 } 1787 let callNow = immediate & !timeout 1788 clearTimeout(timeout); 1789 timeout = setTimeout(later, wait); 1790 if (callNow) func.apply(context, args) 1791 } 1792 } 1793 function fixSliderBar() { 1794 let maxWidth = document.body.clientWidth 1795 const leftBar = document.getElementById("left-nav") 1796 const content = document.getElementById("content") 1797 const rightContent = document.getElementById("right-content") 1798 const footContent = document.getElementById("footer-content") 1799 const fixedTitle = document.getElementById("fixed-title") 1800 const flexRow = rightContent.parentNode 1801 const clientHeight = window.innerHeight 1802 if (maxWidth >= 992) { 1803 let isClpEmbed = false 1804 try { 1805 isClpEmbed = sessionStorage.getItem('clpEmbedEnv') === '1' 1806 || new URLSearchParams(window.location.search).get('clpEmbedEnv') === '1' 1807 } catch (e) { 1808 } 1809 if (isClpEmbed) { 1810 leftBar.style.position = 'static' 1811 leftBar.style.top = '' 1812 leftBar.style.bottom = '' 1813 leftBar.style.height = '' 1814 leftBar.style.minHeight = '' 1815 leftBar.style.left = '' 1816 leftBar.style.width = '' 1817 flexRow.style.paddingLeft = '' 1818 rightContent.style.marginLeft = '' 1819 rightContent.style.minHeight = '0' 1820 try { 1821 fixedTitle.style.display = 'none' 1822 } catch (e) { 1823 } 1824 leftBar.style.maxHeight = '' 1825 leftBar.style.overflow = '' 1826 const contentHeight = rightContent.offsetHeight 1827 if (contentHeight > 0 && leftBar.scrollHeight > contentHeight) { 1828 leftBar.style.maxHeight = contentHeight + 'px' 1829 leftBar.style.overflow = 'hidden auto' 1830 } 1831 return 1832 } 1833 if (leftBar.getBoundingClientRect().top <= 0) { 1834 //float in top on footer 1835 const footerHidden = footContent.offsetHeight === 0 1836 let heightVary = footContent.getBoundingClientRect().bottom - clientHeight 1837 let varyHeight = footContent.offsetHeight - heightVary 1838 if (!footerHidden && varyHeight >= 0 && heightVary <= footContent.offsetHeight) { 1839 //footer show 1840 if(!leftBar.classList.contains('neonfront-p2p-portal-left-nav')) { 1841 leftBar.style.bottom = varyHeight + 'px' 1842 leftBar.style.height = (clientHeight - varyHeight) + 'px' 1843 } else { 1844 leftBar.style.bottom = '0px' 1845 leftBar.style.height = clientHeight + 'px' 1846 } 1847 rightContent.style.minHeight = (clientHeight - varyHeight) + 'px' 1848 leftBar.style.overflow = 'hidden auto' 1849 } else { 1850 // footer hide 1851 leftBar.style.height = clientHeight + 'px' 1852 leftBar.style.bottom = '' 1853 rightContent.style.minHeight = clientHeight + 'px' 1854 leftBar.style.overflow = 'hidden auto' 1855 } 1856 if (leftBar.style.position !== 'fixed') { 1857 const leftBarWidth = leftBar.offsetWidth || 260 1858 leftBar.style.position = 'fixed' 1859 leftBar.style.top = '0' 1860 leftBar.style.width = leftBarWidth + 'px' 1861 flexRow.style.paddingLeft = leftBarWidth + 'px' 1862 rightContent.style.marginLeft = '' 1863 } 1864 leftBar.style.left = flexRow.getBoundingClientRect().left + 'px' 1865 try { 1866 fixedTitle.style.display = '' 1867 } catch (e) { 1868 } 1869 } 1870 if (content.getBoundingClientRect().top > 0) { 1871 //roll back 1872 leftBar.style.position = 'static' 1873 leftBar.style.top = '' 1874 leftBar.style.bottom = '' 1875 leftBar.style.left = '' 1876 leftBar.style.width = '' 1877 flexRow.style.paddingLeft = '' 1878 rightContent.style.marginLeft = '' 1879 leftBar.style.minHeight = '' 1880 rightContent.style.minHeight = '0' 1881 try { 1882 fixedTitle.style.display = 'none' 1883 } catch (e) { 1884 } 1885 } 1886 } else { 1887 //roll back 1888 leftBar.style.position = 'static' 1889 leftBar.style.top = '' 1890 leftBar.style.bottom = '' 1891 leftBar.style.left = '' 1892 leftBar.style.width = '' 1893 flexRow.style.paddingLeft = '' 1894 rightContent.style.marginLeft = '' 1895 leftBar.style.minHeight = '' 1896 rightContent.style.minHeight = '0' 1897 try { 1898 fixedTitle.style.display = 'none' 1899 } catch (e) { 1900 } 1901 } 1902 } 1903 const preFix = setSliderBar(function() { 1904 fixSliderBar(); 1905 }, 4); 1906 try { 1907 const leftBar = document.getElementById("left-nav") 1908 leftBar.style.maxHeight = window.innerHeight + 'px' 1909 leftBar.style.overflow = 'hidden auto' 1910 window.addEventListener('scroll',preFix) 1911 window.addEventListener('resize',preFix) 1912 } catch (ignore) { 1913 //without sidebar not need fix 1914 } 1915</script>
1915 1916 1917 1918 1919</body> 1920</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.