PageSourceSearch

https://www.kommunikasjon.no/_/service/no.seeds.kom/asset/000001a0ce442e90/js/kom/registerEvent.js

js kommunikasjon.no collected 2026-10-02 12:25:15 UTC 31,491 bytes, 918 lines download raw bytes

1$(document).ready(function () {
2	// Helper function to parse URL query parameters
3	function url_query (query) {
4		query = query.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]')
5		const expr = '[\\?&]' + query + '=([^&#]*)'
6		const regex = new RegExp(expr)
7		const results = regex.exec(window.location.href)
8		if (results !== null) {
9			return decodeURIComponent(results[1].replace(/\+/g, ' '))
10		} else {
11			return false
12		}
13	}
14
15	// Check for avtalegiro success status in URL
16	const avtalegiroStatus = url_query('status')
17	if (avtalegiroStatus === 'ok') {
18		// Find the "Min profil" heading
19		const minProfilHeading = $('h2').filter(function () {
20			return $(this).text().trim() === 'Min profil'
21		})
22
23		if (minProfilHeading.length > 0) {
24			// Check if message already exists to avoid duplicates
25			const parentContainer = minProfilHeading.parent()
26			let successMessageElement = parentContainer.find('.avtalegiro-success-message').first()
27
28			if (successMessageElement.length === 0) {
29				// Create the success message element
30				successMessageElement = $('<div>')
31					.addClass('avtalegiro-success-message alert alert-success alert-dismissible')
32					.html('Avtalegiro-registreringen er fullført!<br><small><strong>Merk:</strong> Det kan ta opptil 1 dag eller mer før registreringen vises i din profil. Dette skyldes at registreringen først må bekreftes av banken før den registreres i vårt system.</small>')
33
34				// Add close button
35				const closeButton = $('<button>')
36					.attr({
37						type: 'button',
38						class: 'close',
39						'aria-label': 'Lukk'
40					})
41					.html('&times;')
42					.on('click', function () {
43						successMessageElement.fadeOut(300, function () {
44							successMessageElement.remove()
45						})
46					})
47
48				successMessageElement.prepend(closeButton)
49
50				// Insert the message before the heading
51				minProfilHeading.before(successMessageElement)
52			} else {
53				// If message already exists, just show it
54				successMessageElement.show()
55			}
56
57			// Clean up URL by removing the status parameter
58			let cleanUrl = window.location.href
59			// Remove ?status=ok or &status=ok
60			cleanUrl = cleanUrl.replace(/[?&]status=ok(&|$)/, function (match, after) {
61				return after === '&' ? '&' : ''
62			})
63			// Clean up trailing ? or &
64			cleanUrl = cleanUrl.replace(/[?&]$/, '')
65			// Fix ?& to ?
66			cleanUrl = cleanUrl.replace(/\?&/, '?')
67
68			if (cleanUrl !== window.location.href) {
69				window.history.replaceState({}, document.title, cleanUrl)
70			}
71		} else {
72			// Check for corporate heading layout (hero-corporate__text)
73			const heroCorporateText = $('.hero-corporate__text').first()
74			if (heroCorporateText.length > 0) {
75				// Check if message already exists to avoid duplicates
76				let successMessageElement = heroCorporateText.find('.avtalegiro-success-message').first()
77
78				if (successMessageElement.length === 0) {
79					// Create the success message element
80					successMessageElement = $('<div>')
81						.addClass('avtalegiro-success-message alert alert-success alert-dismissible')
82						.html('Avtalegiro-registreringen er fullført!<br><small><strong>Merk:</strong> Det kan ta opptil 1 dag eller mer før registreringen vises i din profil. Dette skyldes at registreringen først må bekreftes av banken før den registreres i vårt system.</small>')
83
84					// Add close button
85					const closeButton = $('<button>')
86						.attr({
87							type: 'button',
88							class: 'close',
89							'aria-label': 'Lukk'
90						})
91						.html('&times;')
92						.on('click', function () {
93							successMessageElement.fadeOut(300, function () {
94								successMessageElement.remove()
95							})
96						})
97
98					successMessageElement.prepend(closeButton)
99
100					// Insert the message at the end of the hero-corporate__text div
101					heroCorporateText.append(successMessageElement)
102				} else {
103					// If message already exists, just show it
104					successMessageElement.show()
105				}
106
107				// Clean up URL by removing the status parameter
108				let cleanUrl = window.location.href
109				// Remove ?status=ok or &status=ok
110				cleanUrl = cleanUrl.replace(/[?&]status=ok(&|$)/, function (match, after) {
111					return after === '&' ? '&' : ''
112				})
113				// Clean up trailing ? or &
114				cleanUrl = cleanUrl.replace(/[?&]$/, '')
115				// Fix ?& to ?
116				cleanUrl = cleanUrl.replace(/\?&/, '?')
117
118				if (cleanUrl !== window.location.href) {
119					window.history.replaceState({}, document.title, cleanUrl)
120				}
121			} else {
122				// Fallback to existing successMessageFormEvent if neither "Min profil" heading nor corporate heading found
123				const successMessageElement = $('#successMessageFormEvent')
124				if (successMessageElement.length > 0) {
125					// Set the success message
126					successMessageElement.html('Avtalegiro-registreringen er fullført!<br><small><strong>Merk:</strong> Det kan ta opptil 1 dag eller mer før registreringen vises i din profil. Dette skyldes at registreringen først må bekreftes av banken før den registreres i vårt system.</small>')
127
128					// Make it dismissible by adding a close button if it doesn't exist
129					if (successMessageElement.find('.close').length === 0) {
130						successMessageElement.addClass('alert alert-success alert-dismissible')
131						const closeButton = $('<button>')
132							.attr({
133								type: 'button',
134								class: 'close',
135								'aria-label': 'Lukk'
136							})
137							.html('&times;')
138							.on('click', function () {
139								successMessageElement.fadeOut(300, function () {
140									successMessageElement.remove()
141								})
142							})
143						successMessageElement.prepend(closeButton)
144					}
145
146					// Show the message
147					successMessageElement.show()
148
149					// Clean up URL by removing the status parameter
150					let cleanUrl = window.location.href
151					// Remove ?status=ok or &status=ok
152					cleanUrl = cleanUrl.replace(/[?&]status=ok(&|$)/, function (match, after) {
153						return after === '&' ? '&' : ''
154					})
155					// Clean up trailing ? or &
156					cleanUrl = cleanUrl.replace(/[?&]$/, '')
157					// Fix ?& to ?
158					cleanUrl = cleanUrl.replace(/\?&/, '?')
159
160					if (cleanUrl !== window.location.href) {
161						window.history.replaceState({}, document.title, cleanUrl)
162					}
163				}
164			}
165		}
166	}
167
168	// Check for avtalegiro error or cancel status in URL
169	const avtalegiroErrorStatus = url_query('status')
170	if (avtalegiroErrorStatus === 'cancel' || avtalegiroErrorStatus === 'error' || avtalegiroErrorStatus === 'Error' || avtalegiroErrorStatus === 'Cancel') {
171		// If we are on the corporate welcome page, show an info message that faktura will be used
172		const heroCorporateTextError = $('.hero-corporate__text').first()
173		if (heroCorporateTextError.length > 0) {
174			let errorMessageElement = heroCorporateTextError.find('.avtalegiro-error-message').first()
175
176			if (errorMessageElement.length === 0) {
177				errorMessageElement = $('<div>')
178					.addClass('avtalegiro-error-message alert alert-warning alert-dismissible')
179					.html('Avtalegiro-registreringen ble ikke fullført. <br><small>Faktura vil bli brukt som standard betalingsmåte for medlemskapet ditt.</small>')
180
181				const closeButton = $('<button>')
182					.attr({
183						type: 'button',
184						class: 'close',
185						'aria-label': 'Lukk'
186					})
187					.html('&times;')
188					.on('click', function () {
189						errorMessageElement.fadeOut(300, function () {
190							errorMessageElement.remove()
191						})
192					})
193
194				errorMessageElement.prepend(closeButton)
195				heroCorporateTextError.append(errorMessageElement)
196			} else {
197				errorMessageElement.show()
198			}
199		}
200
201		// Clean up URL by removing status and actNo parameters
202		let cleanUrl = window.location.href
203		// Remove ?status=... or &status=...
204		cleanUrl = cleanUrl.replace(/[?&]status=(cancel|error|Error|Cancel)(&|$)/i, function (match, statusValue, after) {
205			return after === '&' ? '&' : ''
206		})
207		// Remove ?actNo=... or &actNo=...
208		cleanUrl = cleanUrl.replace(/[?&]actNo=[^&]*/g, '')
209		// Clean up trailing ? or &
210		cleanUrl = cleanUrl.replace(/[?&]$/, '')
211		// Fix ?& to ?
212		cleanUrl = cleanUrl.replace(/\?&/, '?')
213
214		if (cleanUrl !== window.location.href) {
215			window.history.replaceState({}, document.title, cleanUrl)
216		}
217	}
218
219	const redirectUrl = $('div[data-redirect-page-url]').data('redirect-page-url')
220	if (redirectUrl) {
221		window.location.replace(redirectUrl)
222	}
223
224	const loginModalControl = $('div.onlyLoginModalControl')
225	if (loginModalControl.length > 0) { $('.login-button').click() }
226
227	const redirectLogin = $('div[data-redirect-login]').data('redirect-login')
228	if (redirectLogin) {
229		$('a.loginModalControl').click(function (e) {
230			e.preventDefault()
231			$('.login-button').click()
232		})
233	}
234
235	const signUpForm = $("#registerEvent input[name='signUpForm']").val()
236
237	if (signUpForm === 'true') {
238		$("#registerEvent select[name='medlemstype']").change(function () {
239			if ($(this).val() == 'Student (fulltid)' || $(this).val() == 'Arbeidssøkende') {
240				$('.workingForm').hide()
241
242				if ($(this).val() == 'Arbeidssøkende') {
243					$('#labelAddress').text('Privatadresse*')
244					$('#labelPostnumber').text('Postnummer*')
245				} else {
246					$('#labelAddress').text('Privatadresse')
247					$('#labelPostnumber').text('Postnummer')
248				}
249			} else if ($(this).val() == 'Er i jobb') {
250				$('.workingForm').show()
251				$('#labelAddress').text('Privatadresse*')
252				$('#labelPostnumber').text('Postnummer*')
253			}
254
255			$('#registerEvent :input').not("select[name='medlemstype']").trigger('change')
256		})
257	}
258
259	/* Used for the form in register event/seminar page and in the form in the minside page */
260
261	$('#successMessageFormEvent').hide()
262	$('#failMessageFormEvent').hide()
263
264	$('span.requiredField').hide()
265	$('span.privatField').hide()
266	$('#invoiceAlert').hide()
267
268	$('#registerEvent').on('submit', function (e) {
269		const submitButton = $(this).find('button[type="submit"]')
270		e.preventDefault()
271
272		// Remove required attribute and disable invoice central fields if invoice_send_central is not selected
273		const invoiceOption = $(this).find("input[name='invoiceOption']:checked").val()
274		if (invoiceOption !== 'invoice_send_central') {
275			$('#invoiceCentralFields input[required]').each(function () {
276				$(this).removeAttr('required')
277				$(this).prop('required', false)
278				$(this).prop('disabled', true)
279			})
280		} else {
281			// Re-enable if invoice_send_central is selected
282			$('#invoiceCentralFields input[required]').each(function () {
283				$(this).prop('disabled', false)
284			})
285		}
286
287		const formData = $(this).serialize()
288
289		const serviceUrl = $("#registerEvent input[name='registerService']").val()
290
291		const failMessage = "Beklager, her skjedde det en feil.<br>Hvis det skjer igjen, ta kontakt med oss<br>pÃ¥ <a href='mailto: [email protected]'>[email protected]</a>"
292		const fieldMissing = 'Felt mangler'
293
294		let dataOK = true
295		const $form = $(this)
296		const currentPaymentMethod = $form.find("input[name='paymentMethod']:checked").val()
297		$('span.requiredField').each(function (idx, it) {
298			const $field = $(it).parent().find('select, input')
299			// Only validate fields that actually have the required attribute
300			const isRequired = $field.prop('required') || $field.attr('required') !== undefined
301			// Skip validation if field is disabled, hidden, or not required
302			const isDisabled = $field.prop('disabled') || $field.closest('.hidden').length > 0 || $field.closest('fieldset.hidden').length > 0
303			const shouldSkip = !isRequired || isDisabled
304
305			if (!shouldSkip && (($field.filter('select').val() == '') || ($field.filter('input').val() == ''))) {
306				dataOK = false
307				$(it).show()
308				$('#failMessageFormEvent').text('Følgende felt mangler.')
309				$('#failMessageFormEvent').show()
310			} else {
311				$(it).hide()
312				$('#failMessageFormEvent').hide()
313			}
314		})
315
316		let signUpMedlem = $(this).find("input[name='signUpForm']").val()
317		signUpMedlem = signUpMedlem && (signUpMedlem == 'true')
318
319		const er_i_jobb = $(this).find("select[name='medlemstype']").val()
320
321		let signUpEvent = $(this).find("input[name='signUpEvent']").val()
322		signUpEvent = signUpEvent && (signUpEvent == 'true')
323
324		// Allow students and Arbeidsledig whitout check radio button
325		const invoiceSelected = ($("input[name='invoiceOption']").length > 0) ? $(this).find("input[name='invoiceOption']:checked").val() : 'none'
326		if (((signUpMedlem && (er_i_jobb == 'Er i jobb' || er_i_jobb == '')) || (signUpEvent)) && (invoiceSelected == undefined)) {
327			dataOK = false
328			$('#invoiceAlert').show()
329			$('#failMessageFormEvent').text('Følgende felt mangler.')
330			$('#failMessageFormEvent').show()
331		} else {
332			$('#invoiceAlert').hide()
333			$('#failMessageFormEvent').hide()
334		}
335
336		if (((signUpMedlem && (er_i_jobb == 'Er i jobb' || er_i_jobb == 'Arbeidssøkende')) || (signUpEvent)) && (invoiceSelected == 'invoice_send_private')) {
337			const address = $(this).find("input[name='address']").val() || ''
338			const postnumber = $(this).find("input[name='postnumber']").val() || ''
339			const city = $(this).find("input[name='city']").val() || ''
340
341			if (address == '') {
342				dataOK = false
343				$("input[name='address']").parent().find('span.privatField').show()
344			} else {
345				$("input[name='address']").parent().find('span.privatField').hide()
346			}
347			if (postnumber == '') {
348				dataOK = false
349				$("input[name='postnumber']").parent().find('span.privatField').show()
350			} else {
351				$("input[name='postnumber']").parent().find('span.privatField').hide()
352			}
353			if (city == '') {
354				dataOK = false
355				$("input[name='city']").parent().find('span.privatField').show()
356			} else {
357				$("input[name='city']").parent().find('span.privatField').hide()
358			}
359
360			if (!signUpEvent) {
361				// Validate payment method (required when private is selected)
362				const paymentMethod = $(this).find("input[name='paymentMethod']:checked").val()
363				if (!paymentMethod) {
364					dataOK = false
365					$('#failMessageFormEvent').text('Følgende felt mangler.')
366					$('#failMessageFormEvent').show()
367				}
368
369				if (!dataOK) {
370					$('#failMessageFormEvent').text('Følgende felt mangler.')
371					$('#failMessageFormEvent').show()
372				}
373			}
374		} else {
375			$("input[name='address']").parent().find('span.privatField').hide()
376			$("input[name='postnumber']").parent().find('span.privatField').hide()
377			$("input[name='city']").parent().find('span.privatField').hide()
378		}
379
380		if ($("#registerEvent select[name='medlemstype']").val() == 'Er i jobb' || $("#registerEvent select[name='medlemstype']").val() == 'Arbeidssøkende') {
381			$('span.privatField').each(function (idx, it) {
382				if (($(it).parent().find('select').val() == '') || ($(it).parent().find('input').val() == '')) {
383					dataOK = false
384					$(it).show()
385					$('#failMessageFormEvent').text('Følgende felt mangler.')
386					$('#failMessageFormEvent').show()
387				} else {
388					$(it).hide()
389					$('#failMessageFormEvent').hide()
390				}
391			})
392		} else {
393			$('span.privatFieldStudent').each(function (idx, it) {
394				if (($(it).parent().find('select').val() == '') || ($(it).parent().find('input').val() == '')) {
395					dataOK = false
396					$(it).show()
397					$('#failMessageFormEvent').text('Følgende felt mangler.')
398					$('#failMessageFormEvent').show()
399				} else {
400					$(it).hide()
401					$('#failMessageFormEvent').hide()
402				}
403			})
404		}
405
406		submitButton.prop('disabled', true)
407		submitButton.css('cursor', 'wait')
408
409		if (dataOK) {
410			withRecaptchaToken(function (token) {
411				const dataToSend = token ? `${formData}&g-recaptcha-response=${encodeURIComponent(token)}` : formData
412				$.ajax({
413					url: serviceUrl,
414					method: 'POST',
415					dataType: 'json',
416					data: dataToSend,
417					success: function (data) {
418						if (data.statusMessage === 'success') {
419							// Handle avtalegiro redirect if avtalegiro data is present
420							if (data.avtalegiro) {
421								submitAvtalegiroForm(data.avtalegiro)
422								return
423							}
424
425							const welcomeFormHeader = document.getElementById('welcome-form-header')
426							if (welcomeFormHeader) {
427								$('#sign-up-header').hide()
428								$('#welcome-form-header').show()
429								$('#registerEvent').hide()
430								welcomeFormHeader.scrollIntoView({ behavior: 'smooth', block: 'center' })
431								$('#welcomeForm').show()
432								$('#welcomeForm input').each(function () {
433									$(this).removeAttr('disabled')
434								})
435							} else {
436								$('#failMessageFormEvent').hide()
437								$('#invoiceAlert').hide()
438
439								const redirectPage = data.linkRedirect
440								if (redirectPage) {
441									window.location.replace(redirectPage)
442								} else {
443									window.location.reload()
444									$(document).scrollTop(0)
445								}
446							}
447						}
448
449						if (data.statusMessage == 'fail') {
450							$('#btn-failure-box').click()
451							$('#failMessageFormEvent').hide()
452							$('#invoiceAlert').hide()
453							$('#successMessageFormEvent').hide()
454							submitButton.prop('disabled', false)
455							submitButton.css('cursor', 'pointer')
456						}
457					},
458					error: function (xhr, status, error) {
459						$('#btn-failure-box').click()
460						$('#failMessageFormEvent').hide()
461						$('#invoiceAlert').hide()
462						$('#successMessageFormEvent').hide()
463						submitButton.prop('disabled', false)
464						submitButton.css('cursor', 'pointer')
465					}
466				})
467			})
468		} else {
469			$('#successMessageFormEvent').hide()
470			$('#failMessageFormEvent').text(fieldMissing)
471			$('#failMessageFormEvent').show()
472			submitButton.prop('disabled', false)
473			submitButton.css('cursor', 'pointer')
474		}
475	})
476
477	$('#welcomeForm').on('submit', function (e) {
478		const submitButtons = $(this).find('button[type="submit"]')
479		submitButtons.prop('disabled', true)
480		submitButtons.css('cursor', 'wait')
481		e.preventDefault()
482
483		const fireButtonId = e.originalEvent.submitter.getAttribute('data-id')
484
485		const signUpFormData = $('#registerEvent').serialize()
486		const formData = $(this).serialize()
487
488		const serviceUrl = $("#registerEvent input[name='registerService']").val()
489
490		const baseData = `${signUpFormData}&${formData}&skipWelcomeForm=${fireButtonId === 'skip-current-information'}`
491
492		withRecaptchaToken(function (token) {
493			const dataToSend = token ? `${baseData}&g-recaptcha-response=${encodeURIComponent(token)}` : baseData
494			$.ajax({
495				url: serviceUrl,
496				method: 'POST',
497				dataType: 'json',
498				data: dataToSend,
499				success: function (data) {
500					if (data.statusMessage === 'success') {
501						// Handle avtalegiro redirect if avtalegiro data is present
502						if (data.avtalegiro) {
503							submitAvtalegiroForm(data.avtalegiro)
504							return
505						}
506
507						$('#failMessageFormEvent').hide()
508						$('#invoiceAlert').hide()
509
510						const redirectPage = data.linkRedirect
511						if (redirectPage) {
512							window.location.replace(redirectPage)
513						} else {
514							window.location.reload()
515							$(document).scrollTop(0)
516						}
517					}
518
519					if (data.statusMessage === 'fail') {
520						$('#btn-failure-box').click()
521						$('#failMessageFormEvent').hide()
522						$('#invoiceAlert').hide()
523						$('#successMessageFormEvent').hide()
524						submitButtons.prop('disabled', false)
525						submitButtons.css('cursor', 'pointer')
526					}
527				},
528				error: function (xhr, status, error) {
529					$('#btn-failure-box').click()
530					$('#failMessageFormEvent').hide()
531					$('#invoiceAlert').hide()
532					$('#successMessageFormEvent').hide()
533					submitButtons.prop('disabled', false)
534					submitButtons.css('cursor', 'pointer')
535				}
536			})
537		})
538	})
539
540	// Student Information
541	$('.studentForm').hide()
542	$("select[name='medlemstype']").change(function () {
543		if ($(this).val() == 'Student (fulltid)') {
544			$('.studentForm').show()
545			$('.studentRequired').prop('required', true)
546		} else {
547			$('.studentForm').val('')
548			$('.studentForm').hide()
549			$('.studentRequired').removeAttr('required')
550			$('.studentRequiredOther').removeAttr('required')
551		}
552	})
553
554	$('#invoiceCentralFields').hide()
555	// Initialize: disable invoice central fields on page load if not selected
556	const initialInvoiceOption = $("input[name='invoiceOption']:checked").val()
557	if (initialInvoiceOption !== 'invoice_send_central') {
558		$('#invoiceCentralFields input[type="text"]').prop('disabled', true)
559	}
560
561	$("input[name='invoiceOption']").click(function () {
562		if ($(this).attr('value') == 'invoice_send_central') {
563			$('#invoiceCentralFields input[type="text"]').attr('required', true)
564			$('#invoiceCentralFields input[type="text"]').prop('required', true)
565			$('#invoiceCentralFields input[type="text"]').prop('disabled', false)
566			$('#invoiceCentralFields').show()
567		} else {
568			$('#invoiceCentralFields input[type="text"]').removeAttr('required')
569			$('#invoiceCentralFields input[type="text"]').prop('required', false)
570			$('#invoiceCentralFields input[type="text"]').prop('disabled', true)
571			$('#invoiceCentralFields').hide()
572		}
573	})
574
575	$('#messageChangePassword').hide()
576	$('#changePasswordForm').on('submit', function (e) {
577		e.preventDefault()
578
579		const failMessageChange = "Beklager, her skjedde det en feil.<br>Hvis det skjer igjen, ta kontakt med oss<br>pÃ¥ <a href='mailto: [email protected]'>[email protected]</a>"
580
581		const formData = $(this).serialize()
582
583		const serviceUrl = $(this).find("input[name='changePasswordService']").val()
584
585		const pass1 = $(this).find("input[name='newPassword']").val()
586		const pass2 = $(this).find("input[name='newPasswordAgain']").val()
587
588		if (pass1.length < 6) {
589			$('#messageChangePassword').text('Passordet må være minst 6 bokstaver')
590			$('#messageChangePassword').show()
591			return false
592		}
593
594		if (pass1 != pass2) {
595			$('#messageChangePassword').text('Begge passordene må være like')
596			$('#messageChangePassword').show()
597			return false
598		}
599
600		$.ajax({
601			url: serviceUrl,
602			method: 'POST',
603			dataType: 'json',
604			data: formData,
605			success: function (data) {
606				if (data.statusMessage == 'success') {
607					$('#messageChangePassword').text('Ditt passord er endret!')
608					$('#messageChangePassword').show()
609				}
610
611				if (data.statusMessage == 'fail') {
612					$('#messageChangePassword').append(failMessageChange)
613					$('#messageChangePassword').show()
614				}
615			},
616			error: function (xhr, status, error) {
617				$('#messageChangePassword').append(failMessageChange)
618				$('#messageChangePassword').show()
619			}
620		})
621	})
622
623	$('#consentEvent').on('submit', function (e) {
624		e.preventDefault()
625
626		const formData = $(this).serialize()
627
628		const serviceUrl = $("#consentEvent input[name='consentService']").val()
629
630		$.ajax({
631			url: serviceUrl,
632			method: 'POST',
633			dataType: 'json',
634			data: formData,
635			success: function (data) {
636				if (data.statusMessage == 'success') {
637					// window.location.replace(redirectAfterLogin);
638					$('#btn-confirmation-box').click()
639					// $("#successMessageFormEvent").show();
640					$('#failMessageFormEvent').hide()
641					$('#invoiceAlert').hide()
642					// $('#registerEvent').trigger("reset");
643
644					$('#modalOk').click(function () {
645						const redirectPage = data.linkRedirect
646						if (redirectPage) {
647							window.location.replace(redirectPage)
648						} else {
649							window.location.reload()
650							$(document).scrollTop(0)
651						}
652					})
653				}
654
655				if (data.statusMessage == 'fail') {
656					// window.location.replace(redirectAfterLogin);
657					$('#btn-failure-box').click()
658					// $("#successMessageFormEvent").show();
659					$('#failMessageFormEvent').hide()
660					$('#invoiceAlert').hide()
661					// $('#registerEvent').trigger("reset");
662
663					$('#modalFailureOk').click(function () {
664						const redirectPage = data.linkRedirect
665						if (redirectPage) {
666							window.location.replace(redirectPage)
667						} else {
668							window.location.reload()
669							$(document).scrollTop(0)
670						}
671					})
672
673					/*  $("#failMessageFormEvent").html( data.error || failMessage );
674					$("#failMessageFormEvent").show(); */
675					$('#successMessageFormEvent').hide()
676				}
677			},
678			error: function (xhr, status, error) {
679				// window.location.replace(redirectAfterLogin);
680				$('#btn-failure-box').click()
681				// $("#successMessageFormEvent").show();
682				$('#failMessageFormEvent').hide()
683				$('#invoiceAlert').hide()
684				// $('#registerEvent').trigger("reset");
685
686				$('#modalFailureOk').click(function () {
687					const redirectPage = data.linkRedirect
688					if (redirectPage) {
689						window.location.replace(redirectPage)
690					} else {
691						window.location.reload()
692						$(document).scrollTop(0)
693					}
694				})
695
696				$('#successMessageFormEvent').hide()
697				/* $("#failMessageFormEvent").html(failMessage);
698				$("#failMessageFormEvent").show(); */
699			}
700		})
701	})
702
703	cancelUserForm()
704	if (signUpForm == 'true') $('#registerEvent :input').trigger('change')
705
706	$('input:radio[name="invoiceOption"]').on('change', function () {
707		const value = $(this).val()
708		if (value === 'invoice_send_private') {
709			$('fieldset[data-id="invoice_send_private"]').show()
710			$('fieldset[data-id="invoice_send_private"] input:required').prop('disabled', false)
711			$('fieldset[data-id="invoice_send_company"]').hide()
712			$('fieldset[data-id="invoice_send_company"] input:required').prop('disabled', true)
713		}
714
715		if (value === 'invoice_send_company') {
716			$('fieldset[data-id="invoice_send_company"]').show()
717			$('fieldset[data-id="invoice_send_company"] input:required').prop('disabled', false)
718			$('fieldset[data-id="invoice_send_private"]').hide()
719			$('fieldset[data-id="invoice_send_private"] input:required').prop('disabled', true)
720		}
721	})
722
723	phoneInputHandler()
724})
725
726/**
727 * Generates a reCAPTCHA v3 token when the form exposes a site key, then runs the
728 * callback with the token. On pages without reCAPTCHA configured (no [data-site-key]
729 * element or grecaptcha unavailable) the callback runs immediately with no token,
730 * so event/course signups and profile updates are unaffected.
731 * @param {(token?: string) => void} callback
732 */
733function withRecaptchaToken (callback) {
734	const siteKeyElement = document.querySelector('[data-site-key]')
735	const siteKey = siteKeyElement && siteKeyElement.getAttribute('data-site-key')
736
737	if (!siteKey || typeof grecaptcha === 'undefined') {
738		callback()
739		return
740	}
741
742	grecaptcha.ready(function () {
743		grecaptcha.execute(siteKey, { action: 'submit' })
744			.then(function (token) {
745				callback(token)
746			})
747			.catch(function () {
748				// On failure to obtain a token, submit without one; the server rejects it.
749				callback()
750			})
751	})
752}
753
754function cancelUserForm () {
755	const form = document.querySelector('#cancelUserForm')
756	if (!form) return
757
758	let serviceUrl
759	const element = form.querySelector('[name="cancelUserService"]')
760	if (element) {
761    	serviceUrl = element.value
762	} else {
763    	serviceUrl = undefined
764	}
765
766	let actNo
767	const elementActNo = form.querySelector('[name="actNo"]')
768	if (elementActNo) {
769		actNo = elementActNo.value
770	} else {
771		actNo = undefined
772	}
773
774	if (!serviceUrl || !actNo) return
775
776	// Adding the event to change the save history chosen option
777	const cancelSaveHistory = form.querySelector('.cancel-user-save-history')
778	const resetSaveHistory = function () {
779		const inputs = cancelSaveHistory.querySelectorAll('input')
780		if (inputs) {
781			inputs.forEach(function (input) {
782				input.setAttribute('checked', '')
783			})
784		}
785	}
786
787	const inputs = cancelSaveHistory.querySelectorAll('input')
788	if (inputs) {
789		inputs.forEach(function (input) {
790			input.addEventListener('click', function () {
791				resetSaveHistory()
792				input.setAttribute('checked', 'checked')
793			})
794		})
795	}
796
797	form.addEventListener('submit', function (e) {
798		e.preventDefault()
799
800		let cancelCode
801		const elementCancelCode = form.querySelector('[name="cancelCode"]')
802		if (elementCancelCode) {
803			cancelCode = elementCancelCode.value
804		} else {
805			cancelCode = undefined
806		}
807		if (!cancelCode) return
808
809		let saveHistoryStr
810		const elementChecked = form.querySelector('.cancel-user-save-history input[checked="checked"]')
811		if (elementChecked) {
812			const value = elementChecked.value
813			if (value) {
814				const parts = value.split(',')
815				if (parts.length > 0) {
816					saveHistoryStr = parts[0]
817				} else {
818					saveHistoryStr = undefined
819				}
820			} else {
821				saveHistoryStr = undefined
822			}
823		} else {
824			saveHistoryStr = undefined
825		}
826
827		const saveHistory = saveHistoryStr === 'true'
828
829		fetch(`${serviceUrl}?actNo=${actNo}&cancelCode=${cancelCode}&saveHistory=${saveHistory}`)
830			.then(res => res.json())
831			.then(data => {
832				const messageContainer = document.querySelector('#confirmation-box h4')
833				if (messageContainer) {
834					messageContainer.innerHTML = 'Du er nå meldt ut!'
835				}
836				const button = document.querySelector('#btn-confirmation-box')
837				if (button) {
838					button.click()
839				}
840
841				const modalOkButton = document.querySelector('#modalOk')
842				if (modalOkButton) {
843					modalOkButton.addEventListener('click', function () {
844						location.reload()
845					})
846				}
847			})
848			.catch(e => {
849				const failureButton = document.querySelector('#btn-failure-box')
850				if (failureButton) {
851					failureButton.click()
852				}
853			})
854	})
855}
856
857/**
858 * Submits the avtalegiro form with the provided data and redirects to the avtalegiro page
859 * @param {Object} avtalegiroData - The avtalegiro response data from the API
860 */
861function submitAvtalegiroForm (avtalegiroData) {
862	if (!avtalegiroData) {
863		console.error('No avtalegiro data provided')
864		return
865	}
866
867	// Extract values from the response data (handling different possible field names)
868	// Use hardcoded defaults as per the form template
869	const companyName = avtalegiroData.companyName
870	const companyAccountNo = avtalegiroData.companyAccountNo
871	const kid = avtalegiroData.KID
872	const amountLimit = avtalegiroData.amountLimit
873	const returnUrl = avtalegiroData.returnUrl
874
875	// Create a form element
876	const form = document.createElement('form')
877	form.method = 'POST'
878	form.action = avtalegiroData.formAction
879	form.style.display = 'none'
880
881	// Create and append form fields
882	const fields = [
883		{ name: 'companyName', value: companyName },
884		{ name: 'companyAccountNo', value: companyAccountNo },
885		{ name: 'kid', value: kid },
886		{ name: 'amountLimit', value: amountLimit },
887		{ name: 'returnUrl', value: returnUrl },
888		{ name: 'notificationDisabled', value: 'true' }
889	]
890
891	fields.forEach(field => {
892		const input = document.createElement('input')
893		input.type = 'hidden'
894		input.name = field.name
895		input.id = field.name
896		input.value = field.value
897		form.appendChild(input)
898	})
899
900	// Append form to body and submit
901	document.body.appendChild(form)
902	form.submit()
903}
904
905/**
906 * Adds event listener to phone number to allow only 8 digits and numbers
907 */
908function phoneInputHandler () {
909	const phoneNumber = document.querySelector('[type="tel"][pattern]')
910
911	if (!phoneNumber) return
912
913	phoneNumber.addEventListener('input', function () {
914		if (String(this.value).length > 8) this.value = String(this.value).slice(0, 8)
915
916		this.value = this.value.replace(/[^0-9]/g, '')
917	})
918}

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.