PageSourceSearch

https://www.lakeway-tx.gov/-1466400618.js

js lakeway-tx.gov collected 2026-10-02 07:44:06 UTC 123,763 bytes, 3,990 lines download raw bytes

1/*
2The following errors were found when attempting to minify this file:
3- Line 37: Parse error. missing : after property id
4- Line 37: Parse error. illegal character
5- Line 37: Parse error. missing ; before statement
6- Line 37: Parse error. illegal character
7- Line 37: Parse error. syntax error
8- Line 38: Parse error. syntax error
9- Line 39: Parse error. syntax error
10- Line 40: Parse error. syntax error
11- Line 42: Parse error. syntax error
12- Line 43: Parse error. illegal character
13- Line 43: Parse error. missing ) after argument list
14- Line 43: Parse error. illegal character
15- Line 43: Parse error. syntax error
16- Line 44: Parse error. syntax error
17- Line 45: Parse error. syntax error
18- Line 46: Parse error. syntax error
19- Line 47: Parse error. syntax error
20- Line 49: Parse error. syntax error
21- Line 51: Parse error. missing ; before statement
22- Line 59: Parse error. syntax error
23- Line 61: Parse error. syntax error
24- Line 66: Parse error. invalid return
25- Line 67: Parse error. syntax error
26- Line 69: Parse error. missing ; before statement
27- Line 73: Parse error. syntax error
28- Line 74: Parse error. syntax error
29- Line 75: Parse error. syntax error
30- Line 77: Parse error. syntax error
31- Line 79: Parse error. missing ; before statement
32- Line 85: Parse error. illegal character
33- Line 85: Parse error. missing ; before statement
34- Line 85: Parse error. illegal character
35- Line 86: Parse error. syntax error
36- Line 87: Parse error. syntax error
37- Line 90: Parse error. syntax error
38- Line 93: Parse error. illegal character
39- Line 93: Parse error. missing ; before statement
40- Line 93: Parse error. illegal character
41- Line 97: Parse error. invalid return
42- Line 98: Parse error. syntax error
43- Line 100: Parse error. missing ; before statement
44- Line 101: Parse error. syntax error
45- Line 102: Parse error. syntax error
46- Line 103: Parse error. syntax error
47- Line 108: Parse error. invalid return
48- Line 113: Parse error. missing ; after for-loop initializer
49- Line 113: Parse error. missing ; before statement
50- Line 120: Parse error. syntax error
51- Line 124: Parse error. syntax error
52- Line 127: Parse error. syntax error
53- Line 129: Parse error. syntax error
54- Line 131: Parse error. syntax error
55- Line 132: Parse error. syntax error
56- Line 133: Parse error. syntax error
57- Line 398: Parse error. missing ; before statement
58*/
59// Gets Json object using a given url.
60function GetJson(url) {
61	var result;
62	$.ajaxSetup({ async: false });
63	$.post(url, function (data) {
64		result = data;
65	});
66	$.ajaxSetup({ async: true });
67	return result;
68}
69
70function maxLength(field, maxChars) {
71	if (field.value.length >= maxChars) {
72		event.returnValue = false;
73		return false;
74	}
75}
76
77function maxLengthPaste(field, maxChars) {
78	var copyText = field.value + window.clipboardData.getData("Text");
79	field.value = copyText.substr(0, maxChars);
80	if ((copyText.length) > maxChars) {
81		return false;
82	}
83	event.returnValue = true;
84}
85
86function appendFilesToInput(appendInput, mainFileInput) {
87	const valid = validateMultiFileUpload(appendInput, true);
88	if (!valid) {
89		alert("The file you are trying to upload is not an allowed file type or has an invalid file name. These are the accepted characters: A-z 0-9 ~ ! ( ) - + = [ ] { } , . _");
90		appendInput.value = null;
91		return;
92	}
93	const dt = new DataTransfer();
94	const originalFiles = Array.from(mainFileInput.files);
95	const existingSet = new Set(originalFiles.map(({ name, size, lastModified }) => `${name}-${size}-${lastModified}`));
96	originalFiles.forEach(file => {
97		dt.items.add(file);
98	})
99	const addedFiles = Array.from(appendInput.files);
100	addedFiles.forEach(file => {
101		if (!existingSet.has(`${file.name}-${file.size}-${file.lastModified}`)) {
102			dt.items.add(file);
103		}
104	})
105	mainFileInput.files = dt.files;
106	mainFileInput.dispatchEvent(new Event("change"));
107}
108
109function fileAppender(mainFileInput) {
110	const li = document.createElement("li");
111	const label = document.createElement("label");
112	label.innerHTML = '<span class="visuallyhidden">Add Files</span><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" aria-hidden="true"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>'
113	const appendInput = document.createElement("input");
114	appendInput.type = "file";
115	appendInput.multiple = true;
116	appendInput.className = "visuallyhidden";
117	appendInput.addEventListener("change", e => {
118		appendFilesToInput(appendInput, mainFileInput);
119	});
120	label.appendChild(appendInput);
121	const placeholder = document.createElement("span");
122	li.appendChild(placeholder);
123	li.appendChild(label);
124	return li;
125}
126
127function removeFileFromInput(input, idx) {
128	const dt = new DataTransfer();
129	const files = Array.from(input.files);
130	files.splice(idx, 1);
131	files.forEach(file => {
132		dt.items.add(file);
133	});
134	input.files = dt.files;
135}
136
137function listItemFile(input, file, idx) {
138	const li = document.createElement("li");
139	const fileNameSpan = document.createElement("span");
140	fileNameSpan.textContent = file.name;
141	li.appendChild(fileNameSpan);
142	const removeButton = document.createElement("button");
143	removeButton.title = `Remove ${file.name}`;
144	removeButton.addEventListener("click", e => {
145		e.preventDefault();
146		removeFileFromInput(input, idx);
147		input.dispatchEvent(new Event("change"));
148	});
149	removeButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="darkred" aria-hidden="true"><path d="m336-280 144-144 144 144 56-56-144-144 144-144-56-56-144 144-144-144-56 56 144 144-144 144 56 56ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"></path></svg>';
150	const removeButtonSpan = document.createElement("span");
151	removeButtonSpan.textContent = `Remove ${file.name}`;
152	removeButtonSpan.className = "visuallyhidden";
153	removeButton.appendChild(removeButtonSpan);
154	li.appendChild(removeButton);
155	return li;
156}
157
158function listFileInputFiles(fileInput) {
159	if (fileInput.nextElementSibling?.className === "file-list") {
160		fileInput.nextElementSibling.remove();
161	}
162	const files = fileInput.files || [];
163	const valid = files.length && validateMultiFileUpload(fileInput, true)
164	if (!valid) {
165		fileInput.value = null;
166		return;
167	}
168	if (files.length > 1) {
169		const ul = document.createElement("ul");
170		ul.className = "file-list";
171		for (let i = 0; i < files.length; i++) {			
172			const li = listItemFile(fileInput, files[i], i);
173			ul.appendChild(li);
174		}
175		const fileAppenderLi = fileAppender(fileInput);
176		ul.appendChild(fileAppenderLi);
177		fileInput.after(ul);
178	}
179}
180
181function initFileInputs() {
182	if (!((window?.FeatureToggles?.isActive?.("CMS.FormCenter.MultipleFileUploadEnhancement")) || (window?.FeatureToggles?.features?.["CMS.FormCenter.MultipleFileUploadEnhancement"]))) {
183		return;
184	}
185	document.querySelectorAll(".FileUpload input[type='file']").forEach(fileInput => {
186		listFileInputFiles(fileInput);
187		fileInput.addEventListener("change", e => {
188			listFileInputFiles(fileInput)
189		})
190	});
191}
192;
193/// <reference path="../../../../Scripts/json2.js">
194/// <reference path="../../../../Scripts/HtmlExtensionSupport.js">
195/// <reference path="../../../../Scripts/UrlLibrary.js">
196/// <reference path="../../../../Common/GlobalJSFunctionsDetail.js" />
197/// <reference path="Conditions.js" />
198/// <reference path="Validation.js" />
199/// <reference path="/Assets/Scripts/DynamicForm/PrintSubmission.js" />
200/// <reference path="../../../../Assets/Scripts/DateTimePicker/cp.datetimepicker.js" />
201
202//////// ENUMERATIONS ///////////
203var FormCenterHomeJS = (function ($) {
204	var self = this;
205
206	// This value is set on the ItemDetailFE.ascx page, using a value from the
207	// View Model.
208	self.submissionURL = '';
209
210	return self;
211}(jQuery));
212
213var FormCenterHomeScriptResources = GetJson("/FormCenter/Localization");
214
215// Field formats.
216var FieldValidation = {
217	Any: 0,
218	Letters: 1,
219	Numeric: 2,
220	PhoneNumber: 3,
221	PostalCode: 4,
222	EmailAddress: 5,
223	RegEx: 6,
224	Currency: 7,
225	Date: 8,
226	Time: 9,
227	DateTime: 10,
228	DateSpan: 11,
229	TimeSpan: 12,
230	DateTimeSpan: 13
231};
232
233// Supported field types.
234var FieldTypes = {
235	ShortAnswer: 1,
236	LongAnswer: 2,
237	Checkboxes: 3,
238	RadioButtons: 4,
239	Dropdown: 5,
240	FileUpload: 6,
241	ReplyEmail: 10,
242	Password: 11,
243	DateTime: 18,
244	EPayment: 23
245};
246
247//////// GLOBALS ////////////////
248
249// Stores instantiated form validator/condition instances for the current form.
250var formValidators = null;
251var formConditions = null;
252
253// Use with form submissions.
254var redirectNewWindow = null;
255
256//////// SUPPORT METHODS ////////f
257
258// Shows extra information for a form detail.
259function moreInfo(id) {
260	changeInfo(id, 'addClass', 'removeClass');
261}
262
263// Hides extra information for a form detail.
264function lessInfo(id) {
265	changeInfo(id, 'removeClass', 'addClass');
266}
267
268// Internal. Hides or shows extra information.
269function changeInfo(id, lessFn, moreFn) {
270	$([document.getElementById('spnLess' + id), document.getElementById('lnkMore' + id)])[lessFn]('hidden');
271	$(document.getElementById('spnMore' + id))[moreFn]('hidden');
272}
273
274// Assigns bulk action checkbox group to jQuery expression.
275function assignBulkCheckGroup($children, $parent) {
276	// Isolate children from parent in event of overlap ($children containing the $parent).
277	// Vastly simplifies the logic in the event handlers by doing this.
278	var $isolatedChildren = $children.filter(
279		function (index) {
280			return $parent.filter(this).length == 0;
281		}
282	);
283
284	// Cache current number of checked children.
285	$isolatedChildren.lengthChecked = $isolatedChildren.filter(':checked').length;
286
287	// Hook childen change.
288	$isolatedChildren.change(function (event) {
289		$isolatedChildren.lengthChecked += (this.checked ? 1 : -1);
290
291		var allChildrenChecked = ($isolatedChildren.lengthChecked == $isolatedChildren.length);
292
293		$parent.each(function () {
294			this.checked = allChildrenChecked;
295		});
296	});
297
298	// Hook parent change.
299	$parent.change(function (event) {
300		var parentChecked = this.checked;
301
302		$isolatedChildren.lengthChecked = this.checked ? $isolatedChildren.length : 0;
303
304		$isolatedChildren.each(function () {
305			this.checked = parentChecked;
306		});
307	});
308}
309
310function initCommon() {
311	// Hack: Internet Explorer 7 mode bizarre display bugs.
312	$('.sidebar .search.noStyles').css('zoom', '1');
313
314	// Hook search category bulk checks.
315	var $bulkCheck = $('#categoryFilter_0');
316	var $bulkGroup = $('.categoryList input[type="checkbox"]');
317
318	assignBulkCheckGroup($bulkGroup, $bulkCheck);
319
320	// Get input jQuery refs.
321	var $inputFCTerm = $('#inputFCTerm');
322	var $inputFCSearch = $('#inputFCSearch');
323
324	// Hook search button and textbox to capture enter key.
325	$inputFCTerm.keydown(function (event) {
326		// If user presses enter, submit for search.
327		switch (event.which) {
328			case 10: // LF
329			case 13: // CR
330				event.preventDefault();
331				$inputFCSearch.click();
332				break;
333		}
334	});
335
336	$inputFCSearch.click(function (event) {
337		event.preventDefault();
338
339		// Build search querystring.
340		var qs = {};
341		var formID = extractFormIDFromURL(location.href);
342		var categoryID = extractCategoryIDFromURL(location.href);
343
344		var searchTerm = $.trim(isNull($inputFCTerm.val(), ''));
345
346		if (formID)
347			qs.formID = formID;
348
349		if (categoryID)
350			qs.categoryID = categoryID;
351
352		if (searchTerm != '')
353			qs.term = searchTerm;
354
355		if (!$bulkCheck[0].checked) {
356			var values = [];
357
358			$bulkGroup.filter(':checked').each(function () {
359				values.push(this.value);
360			});
361
362			if (values.length > 0)
363				qs.categoryFilter = values.join(',');
364		}
365
366		// Set search URL and go.
367		window.location = '/FormCenter/Search' + (new QueryStringBuilder(qs)).toString();
368	});
369
370	// Hook search category dropdown.
371	var $catList = $('#categoryList');
372	var $catListToggle = $('a.mega');
373
374	$catListToggle.click(function (e) {
375		e.preventDefault();
376
377		if ($catList.hasClass('open'))
378			$catList.slideUp(300);
379		else
380			$catList.slideDown(300);
381
382		$catListToggle.toggleClass('active');
383		$catList.toggleClass('open');
384	});
385
386	// Show print dialog if URL contains standard print query string.
387	if (containsPrint(location.href))
388		window.print();
389}
390
391// Initialization for search (Search.aspx view).
392function initSearch() {
393	if (this.wasInit)
394		return;
395
396	this.wasInit = true;
397
398	attachCategoryVisibilityTogglers();
399
400	initCommon();
401}
402
403// Initialization for category/form list (Index.aspx view).
404function initCategoryList() {
405	if (this.wasInit)
406		return;
407
408	this.wasInit = true;
409
410	attachCategoryVisibilityTogglers();
411
412	initCommon();
413}
414
415// Initialization for confirmation (Confirmation.aspx view).
416function initConfirmation() {
417	if (this.wasInit)
418		return;
419
420	this.wasInit = true;
421
422	initCommon();
423}
424
425function initPostSubmissionSpam() {
426	initCommon();
427}
428
429
430// Causes current form to be submitted for printing.
431function printForm(saveData) {
432	if (formValidate()) { //check for valid responses before creating print window
433		var frm = document.aspnetForm;
434		var $form = $(document.aspnetForm);
435		var printPrevType = (getPrintPreviewType() == 1 ? 'Print' : 'Preview');
436		var formID = extractFormIDFromURL(location.href);
437
438		$form.attr('target', 'PrintWindow');
439		// Change target/action to print data.
440		frm.action = '/FormCenter/Print?formID=' + formID + '&' + printPrevType + '=YES&Save=' + (saveData ? 'True' : 'False');
441
442		var savedProgressID = parseInt($('#hdnSavedProgressID').val(), 10);
443
444		if (!isNaN(savedProgressID)) {
445			frm.action = frm.action + '&savedProgressID=' + savedProgressID;
446		}
447
448		submitForm($form, true, saveData, formID);
449	} else {
450		enableDisableSubmit(true);
451	}
452}
453
454function submitFormHandler(e) {
455	try {
456		let json = JSON.parse(this.response);
457
458		if (this.status !== 200 || json.Success !== true) {
459			$('.submissionConfirmationMessage').html("Something went wrong with the submission. Please try again.");
460			$('.submissionConfirmation').show();
461			enableDisableSubmit(true);
462			return;
463		}
464
465		const responseUrl = this.responseURL && new URL(this.responseURL);
466		const saveSubmission = responseUrl && responseUrl.searchParams.get('save') && responseUrl.searchParams.get('save').toLowerCase() === 'true';
467		const doPrint = responseUrl && responseUrl.searchParams.get('print') && responseUrl.searchParams.get('print').toLowerCase() === 'true';
468		const redirectAfterSubmissionSaved = json.Redirect && json.Redirect === true && saveSubmission === true;
469
470		if (redirectNewWindow) {
471			// There are two possible redirects in use:
472			// (1) The regular "submit" redirect for the form vs. category confirmation page.
473			// (2) The "conditional" redirect that is applied when a form condition is met.
474			// redirectNewWindow is the latter; redirectAfterSubmissionSaved below deals with the former.
475			window.open(redirectNewWindow);
476			redirectNewWindow = '';
477		}
478
479		if (redirectAfterSubmissionSaved)
480		{
481			if (json.IsHttps === false) {
482				json.Message = json.Message.replace("https://", "http://");
483			}
484
485			location.href = json.Message;
486		}
487		else {
488			if (saveSubmission === true) {
489				$('.submissionConfirmationMessage').html(json.Message);
490				typeof displayStep === "function" && displayStep(1);
491				$('.submitForm').hide();
492				$('.submissionConfirmation').show();
493			}
494
495			enableDisableSubmit(true);
496		}
497
498		if (doPrint === true) {
499			window.open("/FormCenter/Print?formId=" + json.FormId.toString() + '&save=' + (saveSubmission ? 'True' : 'False'));
500		}
501
502		if (json.Success === true) {
503			document.aspnetForm.reset();
504
505			if (typeof (grecaptcha) !== "undefined")
506			{
507				grecaptcha.reset();
508			}
509		}
510
511		!window.isRemoveSetHeights && typeof SetHeights === "function" && SetHeights();
512	} catch (ex) {
513		console.log(ex);
514	}
515}
516
517function submitForm($form, print, saveSubmission, formID) {
518	var submittedViaWidget = $form.parents(".widgetBody").length > 0;
519
520	serializeSpecialFields();
521
522	if (submittedViaWidget !== true) {
523		var printWindow;
524
525		if (print === true)
526		{
527			printWindow = window.open("", "PrintWindow");
528
529			// Deferred object at the window level, this becomes available on the opened window via window.opener
530			// Whichever view gets rendered will resolve it and pass the appropriate status code.
531			window.deferredStatus = $.Deferred();
532		}
533
534		if (printWindow) {
535			window.deferredStatus.done(function (status) {
536				if (status === CP_DynamicForm_PrintSubmission.StatusCodes.Success) {
537					if (saveSubmission && saveSubmission === true) {
538						window.location = '/FormCenter/Confirmation?formID=' + formID;
539					}
540				} else {
541					printWindow.close();
542
543					if (saveSubmission) {
544						window.location = '/FormCenter/ErrorSubmittingForm?formID=' + formID;
545					}
546				}
547			});
548		}
549
550		$form.submit();
551	}
552	else {
553		var submissionUrl = FormCenterHomeJS.submissionURL + (saveSubmission ? '&save=True' : "");
554		submissionUrl = submissionUrl + (print ? '&print=True' : '');
555
556		var formData = new FormData($form[0]);
557		var xhr = new XMLHttpRequest();
558		xhr.onload = submitFormHandler;
559		xhr.onloadend = ajaxPostBackEnd;
560		xhr.onerror = function() { console.log("A network error occurred with the transaction."); };
561		xhr.open("POST", submissionUrl);
562		xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
563		ajaxPostBackStart('Loading');
564		xhr.send(formData);
565	}
566}
567
568function serializeSpecialFields()
569{
570	submitCheckboxHandler();
571
572	submitRadioHandler();
573
574	submitDateTimeHandler();
575}
576
577// Initialization for form item printing (Print.aspx view).
578function initFormPrint() {
579	if (this.wasInit)
580		return;
581
582	this.wasInit = true;
583
584	initCommon();
585
586	initValidationAndConditions();
587
588	registerFormPrintEvents();
589}
590
591function initValidationAndConditions() {
592	// Register validation.
593	if (typeof getFormValidatorData !== 'undefined') {
594		formValidators = FieldValidator.createMulti(getFormValidatorData());
595	} else {
596		formValidators = [];
597	}
598
599	// Register conditions.
600	if (getFormConditionData) {
601		formConditions = FieldConditions.createMulti(getFormConditionData(), formValidators);
602	} else {
603		formConditions = FieldConditions.createMulti([], formValidators);
604	}
605
606	// Register condition runner and make initial condition check.
607	formConditionsRunner = new FieldConditionsRunner(formConditions, $.noop, true, false); // TODO: Finish up, put debugCondRunnerLogResults for $.noop.
608	formConditionsRunner.run();
609}
610
611// Initialization for form item (Item.aspx view).
612function initForm() {
613
614	if (this.wasInit)
615		return;
616
617	this.wasInit = true;
618
619	initCommon();
620	initValidationAndConditions();
621	initDatePickers();
622	initTimePickers();
623	initFileInputs();
624	registerFormEvents(); // Hook up buttons (submit/cancel/etc).
625}
626
627function initDatePickers() {
628	if ($('.telerikDatePicker').length > 0) {
629		$('.telerikDatePicker').each(function () {
630          if (typeof (cp) !== 'undefined') {
631				var datePickerSelector = this.id ? '#' + this.id : this;
632				cp.datetimepicker && cp.datetimepicker.createDatePicker(datePickerSelector);
633			}
634		});
635	}
636}
637
638function initTimePickers() {
639	if ($('.formCenterTimePicker').length > 0) {
640		$('.formCenterTimePicker').focusout(function () {
641			var text = $(this).val().toLowerCase();
642			if (text != '' && (text.indexOf('am') < 0 && text.indexOf('pm') < 0)) {
643				text = $(this).val().trim() + ' AM';
644				$(this).val(text);
645			}
646		});
647	}
648	else {
649		$('.telerikTimePicker').each(function () {
650			if (typeof (cp) !== 'undefined')
651				cp.datetimepicker && cp.datetimepicker.createTimePicker(this,
652					{
653						format: 'h:i A'
654					});
655		});
656	}
657}
658
659// Registers event handlers for form.
660function registerFormPrintEvents() {
661	$('#btnFormContinue').click(function (event) {
662		event.preventDefault();
663
664		var frm = document.aspnetForm;
665		var formID = extractFormIDFromURL(location.href);
666		var $form = $(document.aspnetForm);
667
668		// Change target/action to confirmation page.
669		frm.action = '/FormCenter/Confirmation?formID=' + formID;
670
671		$form.trigger("submit");
672	});
673}
674
675// Registers event handlers for form.
676function registerFormEvents() {
677	// Remove troublemakers (prevent the jQuery submit handler from ever firing, and not needed for this screen anyways).
678	document.aspnetForm.removeAttribute('onsubmit');
679	document.aspnetForm.onsubmit = null;
680
681	var $form = $(document.aspnetForm);
682
683	// TODO: Plug this into other validation.
684	var wantCopyAddr, $wantCopyAddrLI;
685	var wantCopy = document.getElementById('wantCopy');
686
687	if (wantCopy) {
688		wantCopyAddr = document.getElementById('wantCopyAddress');
689		$wantCopyAddrLI = $(wantCopyAddr.parentNode.parentNode);
690
691		$(wantCopy).change(function (event) {
692			if (this.checked)
693				$wantCopyAddrLI.show();
694			else
695				$wantCopyAddrLI.hide();
696		});
697	}
698
699	/* #2378*/
700	$(document).keydown(function (event) {
701		if (event.keyCode === 13 &&
702			event.target.tagName === 'INPUT' &&
703			event.target.id !== 'btnFormSubmit' &&
704			event.target.tagName !== 'TEXTAREA' &&
705			event.target.tagName !== 'SELECT' &&
706			event.target.getAttribute('data-enable-enter-keypress') !== 'true') {
707			event.preventDefault();
708			return false;
709		}
710		if (event.keyCode === 32 &&
711			event.target.tagName === 'A' &&
712			event.target.getAttribute('role') === 'button') {
713			$(event.target).trigger('click');
714			event.preventDefault();
715			return false;
716		}
717	});
718
719	$form.submit(function () {
720		// Run validation, stop data submission if necessary.
721		if (!formValidate()) {
722			enableDisableSubmit(true);
723			return false;
724		}
725
726		if (isNull(redirectNewWindow, '').trimEnd() != '')
727			window.open(redirectNewWindow);
728
729		// Field types requiring special serialization code (radio/check/file).
730		// The deserialization of dictionaries from forms in MVC 2 is somewhat sensitive.
731		serializeSpecialFields();
732		return true;
733	});
734
735	$('#btnFormSubmit').click(function (event) {
736		event.preventDefault();
737		if (formValidate()) {
738			processSubmit(handleSubmitClick);
739		}
740	});
741
742	$('#btnFormPrint').click(function (event) {
743		event.preventDefault();
744		printForm(false);
745	});
746
747	$('#btnFormSubmitPrint').click(function (event) {
748		event.preventDefault();
749		if (formValidate()) {
750			processSubmit(handleSubmitPrintClick);
751		}
752	});
753
754	$('#btnCalculateTotals').click(function (e) {
755		e.preventDefault();
756
757		submitCheckboxHandler();
758		submitRadioHandler();
759
760		if (formValidate()) {
761			var $form = $(document.aspnetForm);
762
763			$.ajax({
764				url: '/FormCenter/Home/CalculateTotal?formID=' + extractFormIDFromURL(location.href),
765				type: 'POST',
766				data: $(document.aspnetForm).serializeArray(),
767				success: function (response) {
768					openCpModal({
769						title: FormCenterHomeScriptResources.CalculateTotals,
770						className: 'modalCalculateTotal',
771						isFrontEnd: window.location.href.indexOf('/Admin/FormCenter') == -1,
772						htmlContent: response
773					});
774				},
775				error: function (xhr, textStatus, exception) {
776					alert('Error: ' + xhr.statusText + '\nStatus: ' + xhr.status);
777				}
778			});
779		}
780	});
781
782	$('#btnProceedToCheckOut').click(function (e) {
783		proceedToCheckOut(e);
784	});
785
786	if ($('.submissionConfirmationOk').length > 0)
787	{
788		$('.submissionConfirmationOk').unbind('click').click(function () {
789			$('.submitForm').show();
790			$('.submissionConfirmation').hide();
791			!window.isRemoveSetHeights && typeof SetHeights === "function" && SetHeights();
792		})
793	}
794}
795
796function onRecaptchaLoadCallback() {
797	window.gRecaptchaClientId = grecaptcha.render('inline-recaptcha', {
798		'sitekey': document.querySelector('#inline-recaptcha').dataset.sitekey,
799		'badge': 'inline',
800		'size': 'invisible'
801	});
802}
803
804function setRecaptchaResponse(token) {
805	if (!token) {
806		return;
807	}
808
809	var responseFields = document.querySelectorAll('[name="g-recaptcha-response"]');
810	for (var i = 0; i < responseFields.length; i++) {
811		responseFields[i].value = token;
812	}
813}
814
815function processSubmit(callback) {
816	const recaptcha = document.querySelector('.recaptcha');
817	if (!recaptcha) {
818		callback();
819		return;
820	}
821
822	grecaptcha.ready(function() {
823		grecaptcha.execute(window.gRecaptchaClientId, { action: 'submit' }).then(function(token) {
824			setRecaptchaResponse(token);
825			callback();
826		});
827	});
828}
829
830function enableDisableSubmit(enable) {
831	if (enable) {
832		if ($('#btnFormSubmitPrint').length > 0) {
833			$('#btnFormSubmitPrint').removeClass('inactive');
834			$('#btnFormSubmitPrint').click(function (event) {
835				handleSubmitPrintClick();
836			});
837		}
838		if ($('#btnFormSubmit').length > 0) {
839			$('#btnFormSubmit').removeClass('inactive');
840			$('#btnFormSubmit').click(function (event) {
841				event.preventDefault();
842				if (formValidate()) {
843					closeModalDialog('editItemBehavior');
844					processSubmit(handleSubmitClick);
845				}
846			});
847		}
848	} else {
849		if ($('#btnFormSubmitPrint').length > 0) {
850			$('#btnFormSubmitPrint').addClass("inactive");
851			$('#btnFormSubmitPrint').unbind();
852		}
853		if ($('#btnFormSubmit').length > 0) {
854			$('#btnFormSubmit').addClass("inactive");
855			$('#btnFormSubmit').unbind();
856		}
857	}
858}
859
860function handleSubmitClick() {
861	enableDisableSubmit(false);
862
863	var frm = document.aspnetForm;
864
865	frm.action = FormCenterHomeJS.submissionURL;
866
867	var $form = $(frm);
868
869	var formID = extractFormIDFromURL(location.href);
870
871	submitForm($form, false, true, formID);
872}
873
874function handleSubmitPrintClick() {
875	enableDisableSubmit(false);
876	printForm(true);
877}
878
879function proceedToCheckOut(e) {
880	e.preventDefault();
881
882	serializeSpecialFields();
883
884	if (formValidate()) {
885		var savedProgressID = parseInt($('#hdnSavedProgressID').val(), 10);
886
887		var submitUrl = '/FormCenter/Home/ProceedToCheckOut?formID=' + extractFormIDFromURL(location.href);
888
889		if (!isNaN(savedProgressID)) {
890			submitUrl = submitUrl + '&savedProgressID=' + savedProgressID;
891		}
892
893		var $form = $(document.aspnetForm);
894		$form.attr('action', submitUrl);
895		$form.submit();
896	}
897}
898
899function getModalDialogObjects() {
900	return {
901		iframe: document.getElementById('liveEditDialog'),
902		windowElement: $('.modalContainerCP')[0],
903		behavior: $find('editItemBehavior'),
904		titleElement: $('.modalTitle')[0]
905	};
906}
907
908function getBooleanValue(value) {
909	switch (value.toLowerCase()) {
910		case "true": case "yes": case "1": return true;
911		case "false": case "no": case "0": case null: return false;
912		default: return Boolean(string);
913	}
914}
915
916// Validates current form.
917function formValidate() {
918	var assignFocus = true;
919	var ERROR_MSG = FormCenterHomeScriptResources.InvalidEmailAddressFormat2;
920	var wantCopy = document.getElementById('wantCopy');
921
922	if (wantCopy) {
923		wantCopyAddr = document.getElementById('wantCopyAddress');
924		$wantCopyAddrLI = $(wantCopyAddr.parentNode.parentNode);
925
926		if ($wantCopyAddrLI.is(":visible") && wantCopyAddr.value != "") {
927			if (!emailValidate(wantCopyAddr.value)) {
928				errorShow(ERROR_MSG);
929				return false;
930			}
931		}
932		if (wantCopy.checked == false)//if the checkbox is not checked then empty the emailaddress textbox
933			document.getElementById('wantCopyAddress').value = "";
934	}
935	else {
936		//if the checkbox is not checked then empty the emailaddress textbox
937		var wantCopyAddress = document.getElementById('wantCopyAddress');
938		if (wantCopyAddress)
939			document.getElementById('wantCopyAddress').value = "";
940	}
941
942	if (typeof formValidators.keys !== 'undefined') {
943		var liCurrent = $('li.current');
944		var step = "1";
945		if (liCurrent.length > 0) {
946			step = liCurrent.attr('id').replace('liStep', '');
947		}
948
949		var wizardStep = $('#wizard' + step);
950
951		if (wizardStep.length > 0) {
952			wizardStep = wizardStep[0];
953		}
954
955		var checkForInappropriateWords = new Array();
956
957		for (var i = 0, len = formValidators.keys.length; i < len; i++) {
958			var key = formValidators.keys[i];
959
960			if (wizardStep == null || wizardStep.length == 0 || (wizardStep != null && wizardStep.contains(formValidators[key].elem
960Container))) {
961				if (!formValidators[key].validate(assignFocus, checkForInappropriateWords))
962					assignFocus = false;
963			}
964		}
965
966		if (validateInappropriateWords(checkForInappropriateWords)) {
967			assignFocus = false;
968		}
969	}
970
971	return assignFocus;
972}
973
974function validateInappropriateWords(checkForInappropriateWords) {
975	var data = {};
976	var j = 0;
977	var inappropriateWordsFound = false;
978
979	for (j = 0; j < checkForInappropriateWords.length; j++) {
980		data[checkForInappropriateWords[j].id.toString()] = checkForInappropriateWords[j].elemInput.value.trim();
981	}
982
983	var results = HasInappropriateWordsMultiple(data);
984
985	for (j = 0; j < checkForInappropriateWords.length; j++) {
986		if (results[checkForInappropriateWords[j].id.toString()] == true) {
987			checkForInappropriateWords[j].handleInappropriateWords(inappropriateWordsFound == false);
988
989			inappropriateWordsFound = true;
990		}
991	}
992
993	return inappropriateWordsFound;
994}
995
996// Displays error message if email validation failed
997function errorShow(message) {
998	var elemContainer = $('.anonEmail');
999	elemContainer.addClass('error');
1000
1001	if (elemContainer.find('.explanation').length == 0) {
1002		var errorElemMsg = document.createElement('p');
1003		errorElemMsg.className = 'explanation';
1004		errorElemMsg.innerHTML = message;
1005		elemContainer.append(errorElemMsg);
1006	}
1007}
1008
1009// Determines if URL contains print querystring.
1010function containsPrint(url) {
1011	return url.search(/(&|\?)print\=yes(&.*|)$/i) > -1;
1012}
1013
1014
1015// Extracts CategoryID identifier from URL specified.
1016function extractCategoryIDFromURL(url) {
1017
1018	url = url.toLowerCase();
1019	var indexOfForm = url.lastIndexOf("/formcenter/");
1020	if (indexOfForm > -1) {
1021		//extract the categoryurl
1022		var formURL = url.substr(indexOfForm + 12);
1023
1024
1025		//check whether u have formid appended
1026
1027		if (formURL.indexOf("/") > -1)
1028			formURL = formURL.substr(0, formURL.indexOf("/"));
1029		//check wheter the url has categoryName
1030		var indexOfHypen = formURL.lastIndexOf("-");
1031		var categoryID = 0;
1032		if (indexOfHypen > -1)
1033			categoryID = formURL.substr(indexOfHypen + 1);
1034		else
1035			categoryID = formURL;
1036		return categoryID;
1037	}
1038	else
1039		return null;
1040}
1041
1042
1043// Extracts form identifier from URL specified.
1044function extractFormIDFromURL(url) {
1045	return parseInt($('#hdnFormID').val(), 10);
1046
1047	//there is some query string appended if so remove those
1048	if (url.indexOf("/?") > -1) {
1049		url = url.substr(0, url.indexOf("/?"));
1050	}
1051
1052	url = url.toLowerCase();
1053	var indexOfForm = url.lastIndexOf("/formcenter/");
1054	if (indexOfForm > -1) {
1055		//extract the url
1056		var formURL = url.substr(indexOfForm + 12);
1057
1058		if (formURL.indexOf("/") > -1) {
1059			formURL = formURL.substr(formURL.indexOf("/") + 1);
1060			//check wheter the url has categoryName
1061			var indexOfHypen = formURL.lastIndexOf("-");
1062			var formID = 0;
1063			if (indexOfHypen > -1)
1064				formID = formURL.substr(indexOfHypen + 1);
1065			else if (formURL == "")
1066				return null;
1067			else
1068				formID = formURL;
1069
1070			return formID;
1071		}
1072		else
1073			return null;
1074	}
1075	else
1076		return null;
1077}
1078
1079// Attaches expand/collapse handlers to section headers.
1080function attachCategoryVisibilityTogglers() {
1081	$('#FormCenterContent .contentMain').click(function (event) {
1082		var target = event.target;
1083
1084		if (/^lnkLess[0-9]*$/.test(target.id)) {
1085			// Form details should shrink.
1086			lessInfo(parseInt(target.id.substr(7), 10));
1087			event.preventDefault();
1088		}
1089		else if (/^lnkMore[0-9]*$/.test(target.id)) {
1090			// Form details should expand.
1091			moreInfo(parseInt(target.id.substr(7), 10));
1092			event.preventDefault();
1093		}
1094	});
1095}
1096
1097// Called by form submittal to handle radio buttons for serialization.
1098function submitRadioHandler() {
1099	var names = [];
1100	var values = {};
1101	$checkBoxSelector = null;
1102	$webCheckBox = $('div.formWrap ol.cpForm input[type=radio]');
1103	$mobileCheckBox = $('.mobileGuts input[type=radio]');
1104
1105	if ($webCheckBox.length != 0 && $mobileCheckBox.length == 0)
1106		$checkBoxSelector = $webCheckBox;
1107
1108	if ($webCheckBox.length == 0 && $mobileCheckBox.length != 0)
1109		$checkBoxSelector = $mobileCheckBox;
1110	if ($checkBoxSelector != null) {
1111		// Get list of radio inputs and their values.
1112		$checkBoxSelector.each(function () {
1113			if (!names.contains(this.name)) {
1114				names.push(this.name);
1115				values[this.name] = '';
1116			}
1117
1118			if (this.checked)
1119				values[this.name] = this.value;
1120		})
1121	}
1122
1123	// Map collected data to hidden inputs submitted to server.
1124	for (var i = 0, len = names.length; i < len; i++) {
1125		var inputName = names[i];
1126		var id = (inputName.match(/_/g) || []).length == 2 ? inputName.substring(inputName.indexOf('_') + 1) : inputName;
1127		document.getElementById(id).value = values[inputName];
1128	}
1129}
1130
1131// Called by form submittal to handle checkboxes for serialization.
1132function submitCheckboxHandler() {
1133	var names = [];
1134	var values = {};
1135	$checkBoxSelector = null;
1136	$webCheckBox = $('div.formWrap ol.cpForm input[type=checkbox]');
1137	$mobileCheckBox = $('.mobileGuts input[type=checkbox]');
1138
1139	if ($webCheckBox.length != 0 && $mobileCheckBox.length == 0)
1140		$checkBoxSelector = $webCheckBox;
1141
1142	if ($webCheckBox.length == 0 && $mobileCheckBox.length != 0)
1143		$checkBoxSelector = $mobileCheckBox;
1144
1145	// Get list of checkbox inputs and their values.
1146	if ($checkBoxSelector != null) {
1147		$checkBoxSelector.each(function () {
1148			if (!names.contains(this.name)) {
1149				names.push(this.name);
1150				values[this.name] = [];
1151			}
1152
1153            if (this.checked) {
1154                var val = this.value.replace(/target="__blank"/g, 'target="_blank"');
1155				val = val.replace(/\,/g, '_comma_');
1156				if (val.trim() == '')
1157					val = '_empty_value_';
1158				values[this.name].push(val);
1159
1160			}
1161		});
1162	}
1163
1164	// Map collected data to hidden inputs submitted to server.
1165	for (var i = 0, len = names.length; i < len; i++)
1166		document.getElementById(names[i]).value = values[names[i]].join(',');
1167}
1168
1169function submitDateTimeHandler() {
1170	var names = [];
1171	var values = [];
1172
1173	var $datePickers, $timePickers;
1174    if ($('.formCenterDatePicker').length > 0 || $('.formCenterTimePicker').length > 0) {
1175        $datePickers = $('.formCenterDatePicker');
1176        $timePickers = $('.formCenterTimePicker');
1177    }
1178    else {
1179        $datePickers = $('.telerikDatePicker');
1180        $timePickers = $('.telerikTimePicker');
1181    }
1182
1183	$datePickers.each(function () {
1184		if (!names.contains(this.name)) {
1185			names.push(this.name);
1186			values[this.name] = [this.value];
1187		}
1188		else {
1189			values[this.name].push(this.value);
1190		}
1191	});
1192
1193	$timePickers.each(function () {
1194		if (!names.contains(this.name)) {
1195			names.push(this.name);
1196			values[this.name] = ['', '', this.value];
1197		}
1198		else {
1199			if (values[this.name].length == 1) {
1200				values[this.name].push('');
1201			}
1202			values[this.name].push(this.value);
1203		}
1204	});
1205
1206	for (var i = 0, len = names.length; i < len; i++)
1207		document.getElementById(names[i]).value = values[names[i]].join();
1208}
1209
1210$(function () {
1211	$('#aspnetForm,form[name=aspnetForm]').attr('enctype', "multipart/form-data");
1212	$('#aspnetForm,form[name=aspnetForm]').addClass('submitForm');
1213});
1214;
1215
1216/// <reference path="../../../../Scripts/json2.js" />
1217/// <reference path="../../../../Scripts/HtmlExtensionSupport.js" />
1218/// <reference path="../../../../Common/GlobalJSFunctionsDetail.js" />
1219/// <reference path="../../../../Assets/Scripts/InappropriateWords.js" />
1220/// <reference path="Home.js" />
1221
1222// Overridden on a per-form basis. Retrieves validator information for submission validation.
1223//function getFormValidatorData() {
1224//	return [];
1225//}
1226
1227var FormCenterHomeScriptResources = GetJson("/FormCenter/Localization");
1228var originalTextColorRadio;
1229var originalTextColorCheckBox;
1230
1231$.getScript("/Assets/Scripts/InappropriateWords.js");
1232
1233// Used to properly localize strings.
1234String.prototype.format = function () {
1235	var args = arguments;
1236	return this.replace(/{(\d+)}/g, function (match, number) {
1237		return typeof args[number] != 'undefined'
1238			? args[number]
1239			: match
1240			;
1241	});
1242};
1243
1244
1245// Performs validation for a form field.
1246function FieldValidator(elemInput, id, fieldType, isInternal, isRequired, formatValidation, formatValidationCustom, minA
1246nswer, maxAnswer, maxLength) {
1247	var self = this;
1248	this.elemInputIsArray = $.isArray(elemInput);
1249
1250	if (this.elemInputIsArray) {
1251		for (var i = 0, len = elemInput.length; i < len; i++) {
1252			if (typeof (elemInput[i]) == "string")
1253				elemInput[i] = document.getElementById(elemInput[i]);
1254		}
1255
1256		if (elemInput.length > 0 && elemInput[0]) {
1257			this.elemContainer = elemInput[0].parentNode.parentNode.parentNode.parentNode;
1258			this.elemInput = elemInput;
1259		}
1260	}
1261	else {
1262		if (typeof (elemInput) == "string")
1263			elemInput = document.getElementById(elemInput);
1264
1265		if (elemInput) {
1266			if (fieldType === FieldTypes.DatePicker)
1267				this.elemContainer = elemInput.parentNode.parentNode.parentNode.parentNode;
1268			else
1269				this.elemContainer = elemInput.parentNode.parentNode;
1270			this.elemInput = elemInput;
1271		}
1272	}
1273
1274	this.enabled = true;
1275	this.$elemContainer = $(this.elemContainer);
1276	this.fieldType = fieldType;
1277	if (this.fieldType === FieldTypes.FileUpload) {
1278		//When validating <input type="file" />, we need to update the elemInput reference since it is created a new one when failing inside validateFileUpload method - LC
1279		var validateInputFileUpload = function () {
1280			var $this = $(this);
1281			if (!validateMultiFileUpload($this[0], true)) {
1282				alert("The file you are trying to upload is not an allowed file type or has an invalid file name. These are the accepted characters: A-z 0-9 ~ ! ( ) - + = [ ] { } , . _");
1283				self.elemInput.value = null;
1284				self.elemInput.focus();
1285			}
1286		};
1287		$(this.elemInput).attr("change", "").removeAttr("onChange").unbind("change").change(validateInputFileUpload);
1288	}
1289	this.id = id;
1290	this.isInternal = isInternal;
1291	this.isRequired = isRequired;
1292	this.formatValidation = formatValidation;
1293	this.formatValidationCustom = formatValidationCustom;
1294	this.elemErrorNote = null;
1295	this.minAnswer = minAnswer;
1296	this.maxAnswer = maxAnswer;
1297	this.maxLength = maxLength;
1298	this.focusElementIndex = 0;
1299	this.alreadySetFocus = false;
1300	var isRequiredInfoLableDisplayed = false;
1301	if (this.isRequired && !isRequiredInfoLableDisplayed) {
1302		$('#liRequiredFieldInfo').show();
1303		isRequiredInfoLableDisplayed = true;
1304	}
1305}
1306
1307// Static. Creates a single validation object from an options object.
1308FieldValidator.createSingle = function (options) {
1309	return new FieldValidator(
1310		options.elemInput,
1311		options.id,
1312		options.fieldType,
1313		options.isInternal,
1314		options.isRequired,
1315		options.formatValidation,
1316		options.formatValidationCustom,
1317		options.minAnswer,
1318		options.maxAnswer,
1319		options.maxLength);
1320};
1321
1322// Static. Creates array of validation objects from array of option objects.
1323FieldValidator.createMulti = function (optionsArray) {
1324	var key = null;
1325
1326	var ret = {
1327		keys: [],
1328		add: function (validator) {
1329			var key = validator.id;
1330			this[key] = validator;
1331			this.keys.push(key);
1332		}
1333	};
1334
1335	for (var i = 0, len = optionsArray.length; i < len; i++)
1336		ret.add(FieldValidator.createSingle(optionsArray[i]));
1337
1338	return ret;
1339};
1340
1341// Internal.  Used by validation() to ensure the input does not exceed the max length.
1342FieldValidator.prototype.validateMaxLength = function (errorMsg) {
1343	var ERROR_MSG = FormCenterHomeScriptResources.MaxLengthErrorMessage.format(this.maxLength);
1344	if (this.maxLength == null)
1345		return true;
1346	var cleanValue = this.elemInput.value.trim();
1347	if (cleanValue != null && cleanValue.length > this.maxLength) {
1348		errorMsg.push(ERROR_MSG);
1349		return false;
1350	}
1351	return true;
1352};
1353
1354// Internal. Used by validate() to ensure user-enterable fields are phone numbers (of NANP format).
1355FieldValidator.prototype.validatePhone = function (errorMsg) {
1356	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidPhoneNumberFormat);
1357	var origLen = errorMsg.length;
1358
1359	switch (this.fieldType) {
1360		case FieldTypes.ShortAnswer:
1361		case FieldTypes.LongAnswer:
1362		case FieldTypes.Password:
1363			var cleanValue = this.elemInput.value.trim();
1364			if (cleanValue != '' && !phoneValidate(cleanValue, intCountryCode))
1365				errorMsg.push(ERROR_MSG);
1366			break;
1367	}
1368
1369	// Return false if validation check failed (number of errors changed).
1370	return origLen == errorMsg.length;
1371}
1372
1373// Internal. Used by validate() to ensure user-enterable fields are postal codes.
1374FieldValidator.prototype.validatePostal = function (errorMsg) {
1375	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidPostalCode);
1376	var origLen = errorMsg.length;
1377
1378	switch (this.fieldType) {
1379		case FieldTypes.ShortAnswer:
1380		case FieldTypes.LongAnswer:
1381		case FieldTypes.Password:
1382			var cleanValue = this.elemInput.value.trim();
1383
1384			if (cleanValue != '' && !isZipCode(cleanValue, intCountryCode))
1385				errorMsg.push(ERROR_MSG);
1386
1387			break;
1388	}
1389
1390	// Return false if validation check failed (number of errors changed).
1391	return origLen == errorMsg.length;
1392}
1393
1394// Internal. Used by validate() to ensure user-enterable fields are email addresses.
1395FieldValidator.prototype.validateEmail = function (errorMsg) {
1396	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidEmailAddressFormat2);
1397	var origLen = errorMsg.length;
1398
1399	switch (this.fieldType) {
1400		case FieldTypes.ShortAnswer:
1401		case FieldTypes.LongAnswer:
1402		case FieldTypes.Password:
1403		case FieldTypes.ReplyEmail:
1404			var cleanValue = this.elemInput.value.trim();
1405
1406			if (cleanValue != '' && !emailValidate(cleanValue))
1407				errorMsg.push(ERROR_MSG);
1408
1409			break;
1410	}
1411
1412	// Return false if validation check failed (number of errors changed).
1413	return origLen == errorMsg.length;
1414}
1415function getNumericThousandsSeparator() {
1416	var dummy = new Number(11111111);
1417	var thousandSep = dummy.toLocaleString().replace(/1/g, '');
1418	return (thousandSep.length > 0 ? thousandSep.charAt(0) : ',');
1419}
1420// Internal. Used by validate() to ensure user-enterable fields match custom expression.
1421FieldValidator.prototype.validateCustom = function (expr, errorMsg) {
1422	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidGenericField);
1423	var origLen = errorMsg.length;
1424
1425	var customRegExp = new RegExp(expr);
1426
1427	switch (this.fieldType) {
1428		case FieldTypes.ShortAnswer:
1429		case FieldTypes.LongAnswer:
1430		case FieldTypes.Password:
1431			var cleanValue = this.elemInput.value.trim();
1432
1433			if (cleanValue != '' && (!customRegExp.test(cleanValue)))
1434				errorMsg.push(ERROR_MSG);
1435
1436			break;
1437	}
1438
1439	// Return false if validation check failed (number of errors changed).
1440	return origLen == errorMsg.length;
1441}
1442
1443// Internal. Used by validate() to ensure user-enterable fields are letters only.
1444FieldValidator.prototype.validateLetters = function (errorMsg) {
1445	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.LettersOnlyField);
1446	var origLen = errorMsg.length;
1447
1448	var letterRegExp = /^[a-zA-Z ]+$/;
1449
1450	switch (this.fieldType) {
1451		case FieldTypes.ShortAnswer:
1452		case FieldTypes.LongAnswer:
1453		case FieldTypes.Password:
1454			var cleanValue = this.elemInput.value.trim();
1455
1456			if (cleanValue != '' && (!letterRegExp.test(cleanValue)))
1457				errorMsg.push(ERROR_MSG);
1458
1459			break;
1460	}
1461
1462	// Return false if validation check failed (number of errors changed).
1463	return origLen == errorMsg.length;
1464}
1465
1466// Internal. Used by validate() to ensure user-enterable fields are numeric (numbers, decimal separators, and group separators allowed).
1467FieldValidator.prototype.validateNumeric = function (errorMsg) {
1468	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.NumericOnlyField);
1469	var origLen = errorMsg.length;
1470
1471	var numericRegExp = new RegExp("^(([0-9]+?[0-9%G]+?[0-9](|%D[0-9]+))|([0-9]*(|%D[0-9]+)))$"
1472		.replace(/%G/g, RegExp.metaEscape(getNumericThousandsSeparator()))
1473		.replace(/%D/g, RegExp.metaEscape(getNumericDecimalSeparator())));
1474
1475	switch (this.fieldType) {
1476		case FieldTypes.ShortAnswer:
1477		case FieldTypes.LongAnswer:
1478		case FieldTypes.Password:
1479			var cleanValue = this.elemInput.value.trim();
1480
1481			if (cleanValue != '' && (!numericRegExp.test(cleanValue)))
1482				errorMsg.push(ERROR_MSG);
1483
1484			break;
1485	}
1486
1487	// Return false if validation check failed (number of errors changed).
1488	return origLen == errorMsg.length;
1489}
1490
1491FieldValidator.prototype.validateCurrency = function (errorMsg) {
1492	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.CurrencyOnlyField);
1493	var origLen = errorMsg.length;
1494
1495	var value = this.elemInput.value.trim();
1496
1497	if (!this.isValidMoney(value)) {
1498		errorMsg.push(ERROR_MSG);;
1499	}
1500
1501	// Return false if validation check failed (nubmer of errors changed).
1502	return origLen == errorMsg.length;
1503}
1504
1505FieldValidator.prototype.isValidMoney = function (value) {
1506	if (value && value != '')
1507		return /^\$?\s*\d+(,\d{3})*(\.\d{1,2})?$/.test(value);
1508	else
1509		return true;
1510};
1511
1512//#region Date Validation
1513
1514FieldValidator.prototype.validateDate = function (errorMsg) {
1515	var origLen = errorMsg.length;
1516
1517	var date = $(this.elemInput[0]).val();
1518	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidDate);
1519
1520	if (!this.isValidDate(date, this.isRequired)) {
1521		errorMsg.push(ERROR_MSG);
1522	}
1523
1524	// Return false if validation check failed (nubmer of errors changed).
1525	return origLen == errorMsg.length;
1526}
1527
1528FieldValidator.prototype.validateTime = function (errorMsg) {
1529	var origLen = errorMsg.length;
1530
1531	var time = $(this.elemInput[0]).val();
1532	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidTime);
1533
1534	if (!this.isValidTime(time, this.isRequired)) {
1535		errorMsg.push(ERROR_MSG);
1536	}
1537
1538	// Return false if validation check failed (nubmer of errors changed).
1539	return origLen == errorMsg.length;
1540}
1541
1542FieldValidator.prototype.validateDateTime = function (errorMsg) {
1543	var origLen = errorMsg.length;
1544
1545	var date = $(this.elemInput[0]).val();
1546
1547	var time = $(this.elemInput[1]).val();
1548
1549	var validDate = this.isValidDate(date, this.isRequired);
1550
1551	var validTime = this.isValidTime(time, this.isRequired);
1552	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.InvalidDateTime);
1553
1554	if (!validDate && !validTime) {
1555		if (!this.alreadySetFocus) {
1556			this.focusElementIndex = 0;
1557			this.alreadySetFocus = true;
1558		}
1559		errorMsg.push(ERROR_MSG);
1560	}
1561	else if (!validDate) {
1562		if (!this.alreadySetFocus) {
1563			this.focusElementIndex = 0;
1564			this.alreadySetFocus = true;
1565		}
1566		errorMsg.push(ERROR_MSG);
1567	}
1568	else if (!validTime) {
1569		if (!this.alreadySetFocus) {
1570			this.focusElementIndex = 1;
1571			this.alreadySetFocus = true;
1572		}
1573		errorMsg.push(ERROR_MSG);
1574	}
1575
1576	// Return false if validation check failed (nubmer of errors changed).
1577	return origLen == errorMsg.length;
1578}
1579
1580FieldValidator.prototype.validateDateSpan = function (errorMsg) {
1581	var origLen = errorMsg.length;
1582
1583	var date = $(this.elemInput[0]).val();
1584
1585	var dateSpan = $(this.elemInput[1]).val();
1586
1587	if (!this.isValidDate(date, this.isRequired)) {
1588		if (!this.alreadySetFocus) {
1589			this.focusElementIndex = 0;
1590			this.alreadySetFocus = true;
1591		}
1592		errorMsg.push(FormCenterHomeScriptResources.InvalidStartDate);
1593	}
1594	if (!this.isValidDate(dateSpan, this.isRequired)) {
1595		if (!this.alreadySetFocus) {
1596			this.focusElementIndex = 1;
1597			this.alreadySetFocus = true;
1598		}
1599		errorMsg.push(FormCenterHomeScriptResources.InvalidEndDate);
1600	}
1601	if (!this.isValidDateRange(date, dateSpan, this.isRequired, this.isRequired)) {
1602		if (!this.alreadySetFocus) {
1603			this.focusElementIndex = 0;
1604			this.alreadySetFocus = true;
1605		}
1606		errorMsg.push(FormCenterHomeScriptResources.InvalidDateSpan);
1607	}
1608
1609	// Return false if validation check failed (nubmer of errors changed).
1610	return origLen == errorMsg.length;
1611}
1612
1613FieldValidator.prototype.validateTimeSpan = function (errorMsg) {
1614	var origLen = errorMsg.length;
1615
1616	var time = $(this.elemInput[0]).val();
1617
1618	var timeSpan = $(this.elemInput[1]).val();
1619
1620	if (!this.isValidTime(time, this.isRequired)) {
1621		if (!this.alreadySetFocus) {
1622			this.focusElementIndex = 0;
1623			this.alreadySetFocus = true;
1624		}
1625		errorMsg.push(FormCenterHomeScriptResources.InvalidStartTime);
1626	}
1627
1628	if (!this.isValidTime(timeSpan, this.isRequired)) {
1629		if (!this.alreadySetFocus) {
1630			this.focusElementIndex = 1;
1631			this.alreadySetFocus = true;
1632		}
1633		errorMsg.push(FormCenterHomeScriptResources.InvalidEndTime);
1634	}
1635
1636	if (!this.isValidTimeRange(time, timeSpan, this.isRequired, this.isRequired)) {
1637		if (!this.alreadySetFocus) {
1638			this.focusElementIndex = 0;
1639			this.alreadySetFocus = true;
1640		}
1641		errorMsg.push(FormCenterHomeScriptResources.InvalidTimeSpan);
1642	}
1643
1644	// Return false if validation check failed (nubmer of errors changed).
1645	return origLen == errorMsg.length;
1646}
1647
1648FieldValidator.prototype.validateDateTimeSpan = function (errorMsg) {
1649	var origLen = errorMsg.length;
1650
1651	var date = $(this.elemInput[0]).val();
1652
1653	var dateSpan = $(this.elemInput[1]).val();
1654
1655	var time = $(this.elemInput[2]).val();
1656
1657	var timeSpan = $(this.elemInput[3]).val();
1658
1659	var validDate = this.isValidDate(date, this.isRequired);
1660
1661	var validTime = this.isValidTime(time, this.isRequired);
1662
1663	if (!validDate && !validTime) {
1664		if (!this.alreadySetFocus) {
1665			this.focusElementIndex = 0;
1666			this.alreadySetFocus = true;
1667		}
1668		errorMsg.push(FormCenterHomeScriptResources.InvalidStartDateTime);
1669	}
1670	else if (!validDate) {
1671		if (!this.alreadySetFocus) {
1672			this.focusElementIndex = 0;
1673			this.alreadySetFocus = true;
1674		}
1675		errorMsg.push(FormCenterHomeScriptResources.InvalidStartDate);
1676	}
1677	else if (!validTime) {
1678		if (!this.alreadySetFocus) {
1679			this.focusElementIndex = 2;
1680			this.alreadySetFocus = true;
1681		}
1682		errorMsg.push(FormCenterHomeScriptResources.InvalidStartTime);
1683	}
1684
1685	var validSpanDate = this.isValidDate(dateSpan, this.isRequired);
1686
1687	var validSpanTime = this.isValidTime(timeSpan, this.isRequired);
1688
1689	if (!validSpanDate && !validSpanTime) {
1690		if (!this.alreadySetFocus) {
1691			this.focusElementIndex = 1;
1692			this.alreadySetFocus = true;
1693		}
1694		errorMsg.push(FormCenterHomeScriptResources.InvalidEndDateTime);
1695	}
1696	else if (!validSpanDate) {
1697		if (!this.alreadySetFocus) {
1698			this.focusElementIndex = 1;
1699			this.alreadySetFocus = true;
1700		}
1701		errorMsg.push(FormCenterHomeScriptResources.InvalidEndDate);
1702	}
1703	else if (!validSpanTime) {
1704		if (!this.alreadySetFocus) {
1705			this.focusElementIndex = 3;
1706			this.alreadySetFocus = true;
1707		}
1708		errorMsg.push(FormCenterHomeScriptResources.InvalidEndTime);
1709	}
1710	var isDayBeforeMonth = getDateFormat().toLocaleLowerCase() == "dd/mm/yyyy" ? true : false;
1711	if (!this.isValidDateTimeRange(getDateFromInput(this.elemInput[0], isDayBeforeMonth), getDateFromInput(this.elemInput[1], isDayBeforeMonth), this.isRequired, this.isRequired, time, timeSpan, this.isRequired, this.isRequired)) {
1712		if (!this.alreadySetFocus) {
1713			this.focusElementIndex = 1;
1714			this.alreadySetFocus = true;
1715		}
1716		errorMsg.push(FormCenterHomeScriptResources.InvalidDateTimeSpan);
1717	}
1718
1719	// Return false if validation check failed (nubmer of errors changed).
1720	return origLen == errorMsg.length;
1721}
1722
1723FieldValidator.prototype.isValidDate = function (date, dateRequired) {
1724	var objDate = new dateValidator();
1725
1726	return objDate.dateValidateNew(date, dateRequired, '');
1727}
1728
1729FieldValidator.prototype.isValidTime = function (time, timeRequired) {
1730	var objDate = new dateValidator();
1731
1732	var amIndex = time.toLowerCase().indexOf('am');
1733	var pmIndex = time.toLowerCase().indexOf('pm');
1734
1735	if (amIndex != -1) {
1736		time = time.substring(0, amIndex).replace(" ", "");
1737
1738		if (time.trim() === "") {
1739			return false;
1740		}
1741	}
1742	else if (pmIndex != -1) {
1743		time = time.substring(0, pmIndex).replace(" ", "");
1744
1745		if (time.trim() === "") {
1746			return false;
1747		}
1748	}
1749
1750	return objDate.timeValidate(time, timeRequired, '');
1751}
1752
1753FieldValidator.prototype.isValidTimeRange = function (startTime, endTime, startTimeRequired, endTimeRequired) {
1754	var objDate = new dateValidator();
1755
1756	objDate.ysnAllowTimeOnly = true;
1757	objDate.dtiStartTime = this.stripAMPM(startTime);
1758	objDate.ysnStartTimeRequired = startTimeRequired;
1759	objDate.dtiEndTime = this.stripAMPM(endTime);
1760	objDate.ysnEndTimeRequired = endTimeRequired;
1761	objDate.ysnDatesAreEqual = true;
1762	objDate.strStartAMPM = this.getAMPMString(startTime);
1763	objDate.strEndAMPM = this.getAMPMString(endTime);
1764	objDate.timesAlreadyValidated = true;
1765
1766	return objDate.timeOrderValidate();
1767
1768}
1769
1770FieldValidator.prototype.isValidDateRange = function (startDate, endDate, startDateRequired, endDateRequired) {
1771	var objDate = new dateValidator();
1772	objDate.setStartDate(checkDateFormatReturnUSString(startDate, false));
1773	objDate.setEndDate(checkDateFormatReturnUSString(endDate, false));
1774	objDate.setStartDateRequired(startDateRequired);
1775	objDate.setEndDateRequired(endDateRequired);
1776	objDate.datesAlreadyValidated = true;
1777
1778	return objDate.dateOrderValidateNew();
1779}
1780
1781FieldValidator.prototype.isValidDateTimeRange = function (startDate, endDate, startDateRequired, endDateRequired, startTime, endTime, startTimeRequired, endTimeRequired) {
1782	var objDate = new dateValidator();
1783
1784
1785	objDate.setStartDate(checkDateFormatReturnUSString(startDate, false));
1786	objDate.setEndDate(checkDateFormatReturnUSString(endDate, false));
1787	objDate.setStartDateRequired(startDateRequired);
1788	objDate.setEndDateRequired(endDateRequired);
1789	objDate.ysnAllowEqualDates = true;
1790	objDate.datesAlreadyValidated = true;
1791
1792	var validDateOrder = objDate.dateOrderValidateNew();
1793
1794	objDate.strStartAMPM = this.getAMPMString(startTime);
1795	objDate.strEndAMPM = this.getAMPMString(endTime);
1796	objDate.ysnAllowTimeOnly = true;
1797	objDate.ysnAllowEqualTimes = !objDate.ysnDatesAreEqual;
1798	objDate.dtiStartTime = this.stripAMPM(startTime);
1799	objDate.ysnStartTimeRequired = startTimeRequired;
1800	objDate.dtiEndTime = this.stripAMPM(endTime);
1801	objDate.ysnEndTimeRequired = endTimeRequired;
1802	objDate.timesAlreadyValidated = true;
1803
1804	var validTimeOrder = objDate.timeOrderValidate();
1805
1806	return validDateOrder && validTimeOrder;
1807}
1808
1809FieldValidator.prototype.stripAMPM = function (time) {
1810	var amIndex = time.toLowerCase().indexOf('am');
1811	var pmIndex = time.toLowerCase().indexOf('pm');
1812
1813	if (amIndex != -1) {
1814		time = time.substring(0, amIndex).replace(" ", "");
1815	}
1816	else if (pmIndex != -1) {
1817		time = time.substring(0, pmIndex).replace(" ", "");
1818	}
1819
1820	return time;
1821}
1822
1823FieldValidator.prototype.getAMPMString = function (time) {
1824	var amIndex = time.toLowerCase().indexOf('am');
1825	var pmIndex = time.toLowerCase().indexOf('pm');
1826
1827	var AMPM = '';
1828
1829	if (amIndex != -1) {
1830		AMPM = time.substring(amIndex).replace(" ", "");
1831	}
1832	else if (pmIndex != -1) {
1833		AMPM = time.substring(pmIndex).replace(" ", "");
1834	}
1835	return AMPM;
1836}
1837
1838//#endregion Date Validation
1839
1840//checkbox validation done for min and max answer selcted
1841FieldValidator.prototype.checkBoxValidation = function (errorMsg) {
1842	var origLen = errorMsg.length;
1843	if (this.fieldType == FieldTypes.Checkboxes && ((this.minAnswer != "" && this.minAnswer != undefined) || (this.maxAnswer != "" && this.maxAnswer != undefined))) {
1844		var i = 0, len = this.elemInput.length;
1845		var checkedCount = 0;
1846		for (; i < len; i++) {
1847			if (this.elemInput[i].checked)
1848				checkedCount++;
1849		}
1850		//validation for checkbox min max fields
1851		if (this.minAnswer != "" && this.minAnswer != undefined) {
1852			if (checkedCount < parseInt(this.minAnswer, 10)) // the message is not localized on purpose as this has text and dynamic value
1853				errorMsg.push("This field must have at least " + parseInt(this.minAnswer, 10) + " options selected");
1854		}
1855
1856		if (origLen == errorMsg.length && this.maxAnswer != "" && this.maxAnswer != undefined) {
1857			if (checkedCount > parseInt(this.maxAnswer, 10)) // the message is not localized on purpose as this has text and dynamic value
1858				errorMsg.push("This field can have at most " + parseInt(this.maxAnswer, 10) + " options selected");
1859		}
1860	}
1861
1862	// Return false if validation check failed (number of errors changed).
1863	return origLen == errorMsg.length;
1864};
1865
1866// Internal. Used by validate() to ensure required fields are set.
1867FieldValidator.prototype.validateRequired = function (errorMsg) {
1868	var ERROR_MSG = this.getErrorMessage(FormCenterHomeScriptResources.RequiredField);//FormCenterHomeScriptResources.RequiredField;
1869	var origLen = errorMsg.length;
1870	switch (this.fieldType) {
1871		case FieldTypes.ShortAnswer:
1872		case FieldTypes.LongAnswer:
1873		case FieldTypes.ReplyEmail:
1874		case FieldTypes.Password:
1875		case FieldTypes.FileUpload:
1876		case FieldTypes.CodeSnippet:
1877		case FieldTypes.InputLink:
1878		case FieldTypes.DatePicker:
1879		case FieldTypes.InputImage:
1880			if (this.elemInput != 'undefined' && this.elemInput.value != undefined) {
1881				if (this.elemInput.value.trim() == '')
1882					errorMsg.push(ERROR_MSG);
1883			}
1884			break;
1885		case FieldTypes.Checkboxes:
1886		case FieldTypes.RadioButtons:
1887			var i = 0, len = this.elemInput.length;
1888
1889			for (; i < len; i++) {
1890				if (this.elemInput[i].checked)
1891					break;
1892			}
1893
1894			if (i == len)
1895				errorMsg.push(ERROR_MSG);
1896
1897			break;
1898		case FieldTypes.Dropdown:
1899		case FieldTypes.FormLink:
1900			if (this.elemInput.selectedIndex <= 0)
1901				errorMsg.push(ERROR_MSG);
1902
1903			break;
1904		case FieldTypes.DateTime:
1905			var i = 0, len = this.elemInput.length;
1906
1907			for (; i < len; i++) {
1908				if (this.elemInput[i].value.trim() == '') {
1909					errorMsg.push(ERROR_MSG);
1910					this.focusElementIndex = i;
1911					break;
1912				}
1913			}
1914	}
1915	// Return false if validation check failed (number of errors changed).
1916	return origLen == errorMsg.length;
1917};
1918
1919// Performs validation for field and updates format if necessary.
1920FieldValidator.prototype.validate = function (assignFocusOnFailure, checkForInappropriateWords) {
1921	var errorMsg = [];
1922
1923	// Element not present OR disabled, pass (skipped).
1924	if (this.elemInput == null || !this.enabled)
1925		return true;
1926
1927	if (!this.isRequired || (this.isRequired && this.validateRequired(errorMsg))) {
1928		//checkbox validation done for min and max answer selected
1929		if (this.checkBoxValidation(errorMsg)) {
1930			switch (this.formatValidation) {
1931				case FieldValidation.Letters:
1932					this.validateLetters(errorMsg);
1933					break;
1934				case FieldValidation.Numeric:
1935					this.validateNumeric(errorMsg);
1936					break;
1937				case FieldValidation.Currency:
1938					this.validateCurrency(errorMsg);
1939					break;
1940				case FieldValidation.PhoneNumber:
1941					this.validatePhone(errorMsg);
1942					break;
1943				case FieldValidation.PostalCode:
1944					this.validatePostal(errorMsg);
1945					break;
1946				case FieldValidation.EmailAddress:
1947					this.validateEmail(errorMsg);
1948					break;
1949				case FieldValidation.RegEx:
1950					this.validateCustom(this.formatValidationCustom, errorMsg);
1951					break;
1952				case FieldValidation.Date:
1953					this.validateDate(errorMsg);
1954					break;
1955				case FieldValidation.Time:
1956					this.validateTime(errorMsg);
1957					break;
1958				case FieldValidation.DateTime:
1959					this.validateDateTime(errorMsg);
1960					break;
1961				case FieldValidation.DateSpan:
1962					this.validateDateSpan(errorMsg);
1963					break;
1964				case FieldValidation.TimeSpan:
1965					this.validateTimeSpan(errorMsg);
1966					break;
1967				case FieldValidation.DateTimeSpan:
1968					this.validateDateTimeSpan(errorMsg);
1969					break;
1970			}
1971		}
1972	}
1973	if (this.fieldType === FieldTypes.DatePicker && this.elemInput.value.trim() != '') {
1974		//validate date picker value (based on telerik mvc datePicker)
1975		var datepicker = $(this.elemInput).data("tDatePicker");
1976		if ($(this.elemInput).hasClass('t-state-error') || datepicker.parse(this.elemInput.value.trim()) == null)
1977			errorMsg.push("Invalid date format");
1978	}
1979	if (this.fieldType === FieldTypes.ShortAnswer || this.fieldType === FieldTypes.LongAnswer) {
1980		var validator = this;
1981
1982		if (checkForInappropriateWords != null && typeof (checkForInappropriateWords.push) == 'function') {
1983			checkForInappropriateWords.push(validator);
1984		} else {
1985			if (HasInappropriateWords(this.elemInput.value.trim())) {
1986				$(this.elemInput).addClass('t-state-error');
1987				errorMsg.push(FormCenterHomeScriptResources.InappropriateWords);
1988			}
1989		}
1990	}
1991
1992	if (FeatureToggles.isActive("CMS.FormCenter.EnableServerSideValidationsForSubmissions")
1993		&& this.fieldType === FieldTypes.FileUpload
1994		&& this.elemInput.value.trim() != '') {
1995		if (Math.round((this.elemInput.files[0].size / 1024)) > 20480)
1996			errorMsg.push("Files cannot be larger than 20 MB.");
1997	}
1998
1999	this.validateMaxLength(errorMsg);
2000
2001	if (errorMsg.length > 0 && $(this.elemInput).is(":visible")) {
2002		this.errorShow(errorMsg);
2003
2004		if (assignFocusOnFailure) {
2005			this.focusErrorElement();
2006		}
2007
2008		return false;
2009	} else {
2010		this.errorClear();
2011		return true;
2012	}
2013
2014};
2015
2016// Performs validation for admin edit internal only fields and updates format if necessary.
2017FieldValidator.prototype.validateInternal = function (assignFocusOnFailure, checkForInappropriateWords) {
2018	if (this.isInternal) {
2019		var errorMsg = [];
2020
2021		// Element not present OR disabled, pass (skipped).
2022		if (this.elemInput == null || !this.enabled)
2023			return true;
2024
2025		if (!this.isRequired || (this.isRequired && this.validateRequired(errorMsg))) {
2026			//checkbox validation done for min and max answer selected
2027			if (this.checkBoxValidation(errorMsg)) {
2028				switch (this.formatValidation) {
2029					case FieldValidation.Letters:
2030						this.validateLetters(errorMsg);
2031						break;
2032					case FieldValidation.Numeric:
2033						this.validateNumeric(errorMsg);
2034						break;
2035					case FieldValidation.Currency:
2036						this.validateCurrency(errorMsg);
2037						break;
2038					case FieldValidation.PhoneNumber:
2039						this.validatePhone(errorMsg);
2040						break;
2041					case FieldValidation.PostalCode:
2042						this.validatePostal(errorMsg);
2043						break;
2044					case FieldValidation.EmailAddress:
2045						this.validateEmail(errorMsg);
2046						break;
2047					case FieldValidation.RegEx:
2048						this.validateCustom(this.formatValidationCustom, errorMsg);
2049						break;
2050					case FieldValidation.Date:
2051						this.validateDate(errorMsg);
2052						break;
2053					case FieldValidation.Time:
2054						this.validateTime(errorMsg);
2055						break;
2056					case FieldValidation.DateTime:
2057						this.validateDateTime(errorMsg);
2058						break;
2059					case FieldValidation.DateSpan:
2060						this.validateDateSpan(errorMsg);
2061						break;
2062					case FieldValidation.TimeSpan:
2063						this.validateTimeSpan(errorMsg);
2064						break;
2065					case FieldValidation.DateTimeSpan:
2066						this.validateDateTimeSpan(errorMsg);
2067						break;
2068				}
2069			}
2070		}
2071		if (this.fieldType === FieldTypes.DatePicker && this.elemInput.value.trim() != '') {
2072			//validate date picker value (based on telerik mvc datePicker)
2073			var datepicker = $(this.elemInput).data("tDatePicker");
2074			if ($(this.elemInput).hasClass('t-state-error') || datepicker.parse(this.elemInput.value.trim()) == null)
2075				errorMsg.push("Invalid date format");
2076		}
2077		if (this.fieldType === FieldTypes.ShortAnswer || this.fieldType === FieldTypes.LongAnswer) {
2078			var validator = this;
2079
2080			if (checkForInappropriateWords != null && typeof (checkForInappropriateWords.push) == 'function') {
2081				checkForInappropriateWords.push(validator);
2082			} else {
2083				if (HasInappropriateWords(this.elemInput.value.trim())) {
2084					$(this.elemInput).addClass('t-state-error');
2085					errorMsg.push(FormCenterHomeScriptResources.InappropriateWords);
2086				}
2087			}
2088		}
2089
2090		this.validateMaxLength(errorMsg);
2091
2092		if (errorMsg.length > 0 && $(this.elemInput).is(":visible")) {
2093			this.errorShow(errorMsg);
2094
2095			if (assignFocusOnFailure) {
2096				this.focusErrorElement();
2097			}
2098
2099			return false;
2100		} else {
2101			this.errorClear();
2102			return true;
2103		}
2104	}
2105	else {
2106		return true;
2107	}
2108};
2109
2110FieldValidator.prototype.handleInappropriateWords = function (focus) {
2111	var errorMsg = [];
2112	$(this.elemInput).addClass('t-state-error');
2113	errorMsg.push(FormCenterHomeScriptResources.InappropriateWords);
2114	this.errorShow(errorMsg);
2115	if (focus) {
2116		this.focusErrorElement();
2117	}
2118};
2119
2120FieldValidator.prototype.focusErrorElement = function () {
2121	var scrollIntoView = function (element) {
2122		var offset = $(element).offset();
2123		var elementTop = offset.top;
2124		// Add a 50px padding to the top of the element, just for aesthetics
2125		$(document).scrollTop(elementTop - 150);
2126	};
2127
2128	if (this.elemInputIsArray) {
2129		if ($(this.elemInput).is(":visible")) {
2130			if (this.elemInput.length > this.focusElementIndex) {
2131				this.elemInput[this.focusElementIndex].focus();
2132			}
2133			else {
2134				this.elemInput[0].focus();
2135			}
2136			scrollIntoView(this.elemInput[0]);
2137		}
2138		this.alreadySetFocus = false;
2139		this.focusElementIndex = 0;
2140	}
2141	else {
2142		if ($(this.elemInput).is(":visible")) {
2143			this.elemInput.focus();
2144			scrollIntoView(this.elemInput);
2145		}
2146	}
2147}
2148
2149// Shows error message for field. Called by validate() if field value fails validation.
2150FieldValidator.prototype.errorShow = function (messages) {
2151	if (this.elemErrorNote)
2152		this.errorClear();
2153
2154	// Element not defined, cannot perform operation.
2155	if (this.elemInput == null)
2156		return;
2157
2158	this.$elemContainer.addClass('error');
2159	this.elemErrorNote = [];
2160
2161	$('ol li.error div').addClass('selfClear');
2162
2163	if (this.elemInput != undefined) {
2164		if (this.elemInput["0"] != undefined) {
2165			//Check current element is radio
2166			if (this.elemInput["0"].type == "radio" & !(this.$elemContainer.closest('li').hasClass('error'))) {
2167				this.$elemContainer.closest('li').addClass('error');
2168				originalTextColorRadio = this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color;
2169				this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color = "#800000";
2170			}
2171			else //Check current element is checkbox
2172				if (this.elemInput["0"].type == "checkbox" & !(this.$elemContainer.closest('li').hasClass('error'))) {
2173					this.$elemContainer.closest('li').addClass('error');
2174					originalTextColorCheckBox = this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color;
2175					this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color = "#800000";
2176				}
2177		}
2178	}
2179
2180	for (var i = 0, len = messages.length; i < len; i++) {
2181		var errorElemMsg = document.createElement('p');
2182
2183		errorElemMsg.className = 'explanation';
2184
2185		var multiSelectable = this.elemInput[0] !== undefined && this.elemInput.tagName !== "SELECT";
2186		if (multiSelectable) {
2187			errorElemMsg.id = 'errorMsg' + this.elemInput[0].id;
2188		}
2189		else {
2190			errorElemMsg.id = 'errorMsg' + this.elemInput.id;
2191		}
2192
2193		errorElemMsg.innerHTML = messages[i];
2194
2195		if (this.elemInput != undefined) {
2196			if (this.elemInput["0"] != undefined) {
2197				if (this.elemInput["0"].type == "radio" || this.elemInput["0"].type == "checkbox") {
2198					errorElemMsg.style.backgroundColor = "#940E0D"
2199					errorElemMsg.style.color = "#FFFFFF";
2200					errorElemMsg.style.fontWeight = "bold"
2201					errorElemMsg.style.lineHeight = "1.2"
2202					errorElemMsg.style.width = "94%"
2203					errorElemMsg.style.margin = ".5em 0 0"
2204					errorElemMsg.style.padding = ".5em"
2205				}
2206			}
2207		}
2208
2209		this.elemContainer.appendChild(errorElemMsg);
2210
2211		this.elemErrorNote.push(errorElemMsg);
2212	}
2213	!window.isRemoveSetHeights && typeof SetHeights === "function" && SetHeights();
2214};
2215
2216// Clears error message for field. Called by validate() if field value passes validation.
2217FieldValidator.prototype.errorClear = function () {
2218	if (this.elemInput != undefined) {
2219		if (this.elemInput["0"] != undefined) {
2220			var i = 0, len = this.elemInput.length;
2221			for (; i < len; i++) {
2222				if (this.elemInput[i].checked)
2223					break;
2224			}
2225
2226			if (i != len) {
2227				if (this.elemInput["0"].type == "radio") {
2228					this.$elemContainer.closest('li').removeClass('error');
2229					this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color = originalTextColorRadio;
2230				}
2231				else if (this.elemInput["0"].type == "checkbox") {
2232					this.$elemContainer.closest('li').removeClass('error');
2233					this.$elemContainer.closest("fieldset")[0].childNodes[0].style.color = originalTextColorCheckBox;
2234				}
2235			}
2236		}
2237	}
2238	if (this.elemErrorNote == null)
2239		return;
2240	else if (this.elemInput == null)
2241		return;
2242
2243	if (this.elemErrorNote.length > 0) {
2244		var errorParent = this.elemErrorNote[0].parentNode;
2245
2246		for (var i = 0, len = this.elemErrorNote.length; i < len; i++)
2247			errorParent.removeChild(this.elemErrorNote[i]);
2248
2249		this.elemErrorNote = null;
2250	}
2251
2252	this.$elemContainer.removeClass('error');
2253	!window.isRemoveSetHeights && typeof SetHeights === "function" && SetHeights();
2254};
2255
2256FieldValidator.prototype.getErrorMessage = function (errorTemplateMsg) {
2257	var $fieldElemContainer = $(this.elemContainer);
2258
2259	if (!$fieldElemContainer.hasClass('formFieldContainer'))
2260	{
2261		$fieldElemContainer = $fieldElemContainer.parents('.formFieldContainer');
2262	}
2263
2264	var $fieldLabelElem = $fieldElemContainer.find('.labelForFieldElement');
2265	var fieldLabel = '';
2266
2267	if ($fieldLabelElem.length > 0)
2268	{
2269		fieldLabel = $fieldLabelElem.text().replace(/\*/g, '');
2270	}
2271	else
2272	{
2273		$fieldLabelElem = $fieldElemContainer.find('legend');
2274		if ($fieldLabelElem.length > 0)
2275		{
2276			fieldLabel = $fieldLabelElem.text().replace(/\*/g, '');
2277		}
2278	}
2279
2280	var errorMsg = errorTemplateMsg.format(fieldLabel);
2281
2282	return errorMsg;
2283}
2284;
2285/// <reference path="../../../../Scripts/json2.js"/>
2286/// <reference path="../../../../Scripts/HtmlExtensionSupport.js"/>
2287/// <reference path="../../../../Common/GlobalJSFunctionsDetail.js" />
2288/// <reference path="Home.js" />
2289
2290// Configurable in debug console. Controls behavior of FieldConditionsRunner.log().
2291var condRunnerHideLogDupes = true;
2292
2293// Missing methods for IE
2294if (!Element.prototype.matches) {
2295	Element.prototype.matches =
2296		Element.prototype.msMatchesSelector ||
2297		Element.prototype.webkitMatchesSelector;
2298}
2299
2300if (!Element.prototype.closest) {
2301	Element.prototype.closest = function (s) {
2302		var el = this;
2303
2304		do {
2305			if (Element.prototype.matches.call(el, s)) return el;
2306			el = el.parentElement || el.parentNode;
2307		} while (el !== null && el.nodeType === 1);
2308		return null;
2309	};
2310}
2311
2312////////// Helper Functions ///////////////
2313
2314$("*").focus(function () {
2315	var inputs = $("input[type=text][cp5ph=true], textarea[cp5ph=true]");
2316	if (inputs != null) {
2317		for (var i = 0; i < inputs.length; i++) {
2318			var elementName = inputs[i].getAttribute('id');
2319			if (elementName != null) {
2320				var top = $('#' + elementName).offset().top;
2321				var left = $('#' + elementName).offset().left;
2322				if (top != -2 && left != -2)
2323					$('#ph_' + elementName).offset({ left: (left + 5), top: (top + 5) });
2324			}
2325		}
2326	}
2327});
2328
2329// Helper that handles replacement of special characters.
2330// * value - variable to handle characters of.
2331function HandleCharacters(value) {
2332	return value.replace(/,/g, '_d');
2333}
2334
2335if (Array.prototype.any == null && !$.isFunction(Array.prototype.any)) {
2336	// Returns true if callback condition returns true for any items in array.
2337	// * callback - Callback function with single argument for current index. The 'this' reference points to the array.
2338	Array.prototype.any = function (callback) {
2339		if (this == null)
2340			return false;
2341
2342		for (var i = 0, len = this.length; i < len; i++) {
2343			if (callback.call(this, i))
2344				return true;
2345		}
2346
2347		return false;
2348	}
2349}
2350
2351if (Array.prototype.all == null && !$.isFunction(Array.prototype.all)) {
2352	// Returns true if callback condition returns true for all items in array.
2353	// * callback - Callback function with single argument for current index. The 'this' reference points to the array.
2354	Array.prototype.all = function (callback) {
2355		if (this == null)
2356			return false;
2357
2358		for (var i = 0, len = this.length; i < len; i++) {
2359			if (!callback.call(this, i))
2360				return false;
2361		}
2362
2363		return true;
2364	};
2365}
2366
2367if (Error.argNull == null || !$.isFunction(Error.argNull)) {
2368	// Static helper that creates error when null argument that should not be null is encountered.
2369	// * argName - Name of problematic null argument.
2370	Error.argNull = function (argName) {
2371		return new ReferenceError(argName + " cannot be null");
2372	}
2373}
2374
2375// Overridden on a per-form basis. Retrieves validator information for submission validation.
2376// * validators - Validator dictionary.
2377function getFormConditionData() {
2378	return [];
2379}
2380
2381// Prints useful debugging information for FieldConditionsRunner.run() results. Use as done callback.
2382// Note: When minifiying the JavaScript, this function can/should be removed.
2383// * logs - Log generated by run().
2384function debugCondRunnerLogResults(logs) {
2385	if (logs == null)
2386		throw new Error.argNull("logs");
2387
2388	console.log("## run() started at " + (new Date()) + " ##");
2389
2390	for (var i = 0, iLen = logs.length; i < iLen; i++) {
2391		var log = logs[i];
2392		var resultEx = log.isMet ? " (met)" : " (not met)";
2393
2394		console.log(
2395			"field: " + log.id +
2396			", condIndex: " + log.condIndex +
2397			", action: " + ConditionActions.getName(log.actType) +
2398			", result: " + ConditionRunnerActResult.getName(log.result) + resultEx);
2399
2400		if (log.needRestart)
2401			console.log("-- restart --");
2402	}
2403
2404	console.log("## run() ended ##");
2405	console.log("\t");
2406}
2407
2408// Helper that repositions line siblings by re-assigning left/middle/right classes.
2409// * liSiblingList - Array of LI elements for a form line.
2410function repositionLineSiblings(liSiblingList) {
2411	if (liSiblingList == null)
2412		throw new Error.argNull("liSiblingList");
2413
2414	var sibling, $sibling;
2415	var len = liSiblingList.length;
2416
2417	if (len > 0) {
2418		var operableNodes = [];
2419
2420		for (var i = 0; i < len; i++) {
2421			sibling = liSiblingList[i];
2422			$sibling = $(sibling);
2423
2424			if (!$sibling.hasClass('hidden'))
2425				operableNodes.push($sibling);
2426		}
2427
2428		len = operableNodes.length;
2429
2430		if (len > 0) {
2431			operableNodes[0].removeClass('middle right').addClass('left');
2432
2433			var j = 1;
2434
2435			for (; j < len - 1; j++)
2436				operableNodes[j].removeClass('left right').addClass('middle');
2437
2438			if (j < len)
2439				operableNodes[j].removeClass('left middle').addClass('right');
2440		}
2441	}
2442}
2443
2444// Helper that gets sibling field LI elements for a line field LI element.
2445// * liElem - The LI element for a form field to get line siblings LIs for.
2446function getLineSiblings(liElem) {
2447
2448	if (liElem == null && (window.location.href).toString().toLowerCase().indexOf("print") != -1)
2449		return "";
2450
2451	if (liElem == null)
2452		throw new Error.argNull("liElem");
2453
2454	var nodeList = [];
2455	var startNode = liElem;
2456
2457	// Get start of line.
2458	while (startNode && !$(startNode).hasClass('lineStart'))
2459		startNode = previousElementSibling(startNode);
2460
2461	// Get end of line.
2462	if (startNode) {
2463		var endNode = startNode;
2464		var $endNode = null;
2465
2466		while (endNode != null) {
2467			$endNode = $(endNode);
2468
2469			if ($endNode.hasClass('lineEnd'))
2470				break;
2471
2472			endNode = nextElementSibling(endNode);
2473		}
2474	}
2475
2476	if (startNode && endNode) {
2477		var nodeEnum = startNode;
2478
2479		while (true) {
2480			nodeList.push(nodeEnum);
2481
2482			if (nodeEnum == endNode)
2483				break;
2484
2485			nodeEnum = nextElementSibling(nodeEnum);
2486		}
2487	}
2488
2489	return nodeList;
2490}
2491
2492////////// Enumerations ///////////////////
2493
2494// Condition actions.
2495var ConditionActions = {
2496	None: 0,
2497	Show: 1,
2498	Hide: 2,
2499	Require: 3,
2500	RedirectTo: 4,
2501	getName: function (value) {
2502		for (var k in ConditionActions) {
2503			if (ConditionActions[k] == value)
2504				return k;
2505		}
2506
2507		return null;
2508	}
2509};
2510
2511// Condition comparison types.
2512var ConditionComparison = {
2513	None: 0,
2514	GreaterThan: 1,
2515	LessThan: 2,
2516	EqualTo: 3,
2517	NotEqualTo: 4,
2518	Contains: 5,
2519	Available: 6,
2520	Unavailable: 7,
2521	Between: 8,
2522	getName: function (value) {
2523		for (var k in ConditionComparison) {
2524			if (ConditionComparison[k] == value)
2525				return k;
2526		}
2527
2528		return null;
2529	}
2530};
2531
2532// Condition runner action results.
2533var ConditionRunnerActResult = {
2534	None: 0,
2535	SuccessImplicit: 1,
2536	SuccessExplicit: 2,
2537	SkipDuplicate: 3,
2538	SkipContradiction: 4,
2539	getName: function (value) {
2540		for (var k in ConditionRunnerActResult) {
2541			if (ConditionRunnerActResult[k] == value)
2542				return k;
2543		}
2544
2545		return null;
2546	}
2547};
2548
2549////////// FieldCondition Class ///////////
2550
2551// Internal. Creates instance of FieldCondition class.
2552// * parent - Parent FieldConditions instance.
2553// * condInfo - Object containing properties {compType, compValue, actElemInput, actID, actType, actFieldType, actURL, actURLNewWindow}.
2554function FieldCondition(parent, condInfo) {
2555	if (parent == null)
2556		throw new Error.argNull("parent");
2557	else if (condInfo == null)
2558		throw new Error.argNull("condInfo");
2559
2560	$.extend(this, condInfo);
2561
2562	// Set instance parent.
2563	this.parent = parent;
2564
2565	// Process actElemInput argument.
2566	var actElemInput = this.actElemInput;
2567	this.actElemInputIsArray = $.isArray(actElemInput);
2568
2569	if (this.actElemInputIsArray) {
2570		for (var i = 0, len = actElemInput.length; i < len; i++) {
2571			if (typeof (actElemInput[i]) == "string")
2572				actElemInput[i] = document.getElementById(actElemInput[i]);
2573		}
2574
2575		if (actElemInput.length > 0 && actElemInput[0]) {
2576			this.actElemContainer = actElemInput[0].closest('.formFieldContainer');
2577			this.actElemInput = actElemInput;
2578		}
2579	}
2580	else {
2581		if (typeof (actElemInput) == "string")
2582			actElemInput = document.getElementById(actElemInput);
2583
2584		if (actElemInput) {
2585			this.actElemContainer = actElemInput.closest('.formFieldContainer');
2586			this.actElemInput = actElemInput;
2587		}
2588	}
2589
2590	// Get shared container.
2591	this.$actElemContainer = $(this.actElemContainer);
2592}
2593
2594// Static. Creates multiple instances from list of condition information.
2595FieldCondition.createMulti = function (parent, condList) {
2596	if (parent == null)
2597		throw new Error.argNull("parent");
2598	else if (condList == null)
2599		throw new Error.argNull("condList");
2600
2601	var ret = [];
2602
2603	for (var i = 0, len = condList.length; i < len; i++)
2604		ret.push(new FieldCondition(parent, condList[i]));
2605
2606	return ret;
2607}
2608
2609// Checks if condition is met and performs any necessary action.
2610// * updateUI - Determines if UI is updated after check. Treated as true if null/unspecified.
2611FieldCondition.prototype.check = function (updateUI) {
2612	// TODO: Handle checkboxes/radios/dropdowns when Akila gets that done on back-end.
2613	var thisValue = [];
2614	var compValue = this.compValue;
2615	var isMet = false;
2616
2617	switch (this.actFieldType) {
2618		case FieldTypes.Checkboxes:
2619			for (var i = 0, len = this.actElemInput.length; i < len; i++) {
2620				if (this.actElemInput[i].checked)
2621					thisValue.push(this.actElemInput[i].value.replace(/\,/g, '_comma_'));
2622			}
2623			break;
2624		case FieldTypes.RadioButtons:
2625			for (var i = 0, len = this.actElemInput.length; i < len; i++) {
2626				if (this.actElemInput[i].checked) {
2627					thisValue = [this.actElemInput[i].value];
2628					break;
2629				}
2630			}
2631			break;
2632		case FieldTypes.DateTime:
2633			var tempArray = new Array();
2634			for (var i = 0, len = this.actElemInput.length; i < len; i++) {
2635				tempArray.push([this.actElemInput[i].value])
2636			}
2637			thisValue = [tempArray.join(',')];
2638			break;
2639		default:
2640			thisValue = [this.actElemInput.value];
2641	}
2642
2643	var extractMoneyValue = function (v) {
2644		var stringBeginsWith = function (val, beginString) {
2645			return val.substring(0, beginString.length) === beginString
2646		}
2647		if (v && v != '') {
2648			if (stringBeginsWith(v, '$')) {
2649				return v.substring(1).replace(',', '');
2650			}
2651		}
2652		return v.replace(',', '');
2653	};
2654
2655
2656	var isNum = function (val) {
2657		var extracted = extractMoneyValue(val);
2658		return parseFloat(extracted) === +extracted;
2659	};
2660
2661	var checkAgainst = function (compValue) {
2662		switch (this.compType) {
2663			case ConditionComparison.GreaterThan:
2664				return thisValue.any(function (index) {
2665					if (isNum(this[index]) && isNum(HandleCharacters(compValue))) {
2666						return parseFloat(extractMoneyValue(this[index])) > parseFloat(extractMoneyValue(HandleCharacters(compValue)));
2667					}
2668					return false;
2669				});
2670			case ConditionComparison.LessThan:
2671				return thisValue.any(function (index) {
2672					if (isNum(this[index]) && isNum(HandleCharacters(compValue))) {
2673						return parseFloat(extractMoneyValue(this[index])) < parseFloat(extractMoneyValue(HandleCharacters(compValue)));
2674					}
2675					return false;
2676				});
2677			case ConditionComparison.EqualTo:
2678				if (this.actFieldType == FieldTypes.DateTime) {
2679					if (this.actIsDateTimeSpan) {
2680						return this.checkDateEqualSpan(thisValue[0], compValue);
2681					}
2682					else {
2683						return this.checkDateEqualTo(thisValue[0], compValue);
2684					}
2685				}
2686				else {
2687					return thisValue.any(function (index) {
2688						return (isNull(HandleCharacters(this[index]), '') == isNull(HandleCharacters(compValue), ''));
2689					});
2690				}
2691			case ConditionComparison.NotEqualTo:
2692				return thisValue.any(function (index) { return (isNull(this[index], '').toUpperCase() != isNull(HandleCharacters(compValue), '').toUpperCase()); });
2693				break;
2694			case ConditionComparison.Contains:
2695				var containsExp = new RegExp(RegExp.metaEscape(HandleCharacters(compValue)), 'i');
2696
2697				return thisValue.any(function (index) {
2698					return containsExp.test(this[index]);
2699				});
2700			case ConditionComparison.Unavailable:
2701				return this.$actElemContainer.hasClass('unavailable');
2702			case ConditionComparison.Available:
2703				return !this.$actElemContainer.hasClass('unavailable');
2704			case ConditionComparison.Between:
2705				return this.checkDateBetween(thisValue[0], compValue);
2706				return;
2707			case ConditionComparison.None:
2708			default:
2709				return true;
2710		}
2711	};
2712
2713	switch (this.actFieldType) {
2714		case FieldTypes.Checkboxes:
2715			var compArr = compValue.split(',');
2716
2717			isMet = true;
2718
2719			for (var i = 0, len = compArr.length; i < len; i++) {
2720
2721				if (!checkAgainst.call(this, compArr[i])) {
2722					isMet = false;
2723					break;
2724				}
2725			}
2726			break;
2727		default:
2728			isMet = checkAgainst.call(this, compValue);
2729	}
2730
2731	if (updateUI)
2732		this.doAction(isMet);
2733
2734	return isMet;
2735};
2736
2737// Performs changes to applying field based on condition action and comparison result.
2738FieldCondition.prototype.doAction = function (isMet) {
2739	var validator = (this.parent.validators ? this.parent.validators[this.parent.id] : null);
2740
2741	switch (this.actType) {
2742		case ConditionActions.Show:
2743			this.doActionShow(isMet, validator);
2744			break;
2745		case ConditionActions.Hide:
2746			this.doActionHide(isMet, validator);
2747			break;
2748		case ConditionActions.Require:
2749			this.doActionRequire(isMet, validator);
2750			break;
2751		case ConditionActions.RedirectTo:
2752			this.doActionRedirect(isMet, validator);
2753			break;
2754	}
2755};
2756
2757FieldCondition.prototype.doActionShow = function (isMet, validator) {
2758	if (isMet) {
2759		this.parent.$elemContainer.removeClass('hidden');
2760		this.parent.$elemContainer.removeClass('unavailable');
2761
2762		// Update classes assigned to fields (e.g. since what was "left" may now be hidden and a new "left" is needed).
2763		repositionLineSiblings(getLineSiblings(this.parent.elemContainer));
2764
2765		if (this.parent.$elemContainer.find('label > span') != null && this.parent.$elemContainer.find('label > span').length > 0)
2766			$('#liRequiredFieldInfo').show();
2767
2768		if (validator)
2769			validator.enabled = true;
2770	}
2771	else {
2772		this.parent.$elemContainer.addClass('hidden');
2773		this.parent.$elemContainer.addClass('unavailable');
2774
2775		// Update classes assigned to fields (e.g. since what was "left" may now be hidden and a new "left" is needed).
2776		repositionLineSiblings(getLineSiblings(this.parent.elemContainer));
2777
2778		if (validator)
2779			validator.enabled = false;
2780	}
2781};
2782
2783FieldCondition.prototype.doActionHide = function (isMet, validator) {
2784	if (isMet) {
2785		this.parent.$elemContainer.addClass('hidden');
2786		this.parent.$elemContainer.addClass('unavailable');
2787
2788		// Update classes assigned to fields (e.g. since what was "left" may now be hidden and a new "left" is needed).
2789		repositionLineSiblings(getLineSiblings(this.parent.elemContainer));
2790
2791		if (validator)
2792			validator.enabled = false;
2793	}
2794	else {
2795		this.parent.$elemContainer.removeClass('hidden');
2796		this.parent.$elemContainer.removeClass('unavailable');
2797
2798		// Update classes assigned to fields (e.g. since what was "left" may now be hidden and a new "left" is needed).
2799		repositionLineSiblings(getLineSiblings(this.parent.elemContainer));
2800
2801		if (validator)
2802			validator.enabled = true;
2803	}
2804};
2805
2806FieldCondition.prototype.doActionRequire = function (isMet, validator) {
2807	if (isMet) {
2808		this.parent.$elemReq.removeClass('hidden');
2809
2810		if (validator == null) {
2811			validator = new FieldValidator(this.parent.elemInput, this.parent.id, this.parent.fieldType, this.parent.isInternal, true, FieldValidation.Any);
2812			this.parent.validators.add(validator);
2813		}
2814
2815		this.parent.$elemContainer.find('label.labelForFieldElement > span').show();
2816		$('#liRequiredFieldInfo').show();
2817		if (validator)
2818			validator.isRequired = true;
2819	}
2820	else {
2821		this.parent.$elemReq.addClass('hidden');
2822		this.parent.$elemContainer.find('label.labelForFieldElement > span').hide();
2823
2824		if (validator)
2825			validator.isRequired = false;
2826	}
2827};
2828
2829FieldCondition.prototype.doActionRedirect = function (isMet, validator) {
2830	// TODO: Some point alter this to pass in references for submitRedirect/redirectNewWindow. Not ideal at moment to ref. global vars.
2831	var submitRedirect = document.getElementById('submitRedirect');
2832
2833	redirectNewWindow = null;
2834	submitRedirect.value = '';
2835
2836	if (isMet) {
2837		if (this.actURLNewWindow) {
2838			redirectNewWindow = this.actURL;
2839			submitRedirect.value = '';
2840		}
2841		else
2842			submitRedirect.value = this.actURL;
2843	}
2844};
2845
2846// Attachs event handler to field to monitor changes.
2847// * condRunner - FieldConditionsRunner instance to attach.
2848// Note: Calling more than once will have no effect.
2849FieldCondition.prototype.attachRunner = function (condRunner) {
2850	if (condRunner == null)
2851		throw new Error.argNull("condRunner");
2852
2853	// Do not try to bind this if it is an internal field condition and we are not running internal field
2854	// conditions.
2855	if (this.parent.isInternal && !condRunner.runInternal)
2856		return;
2857
2858	if ($.data(this.actElemInput, "runner_chghook") == null) {
2859		var changeHook = function (event) { 
2860			condRunner.run(true); 
2861			!window.isRemoveSetHeights && typeof SetHeights === "function" && SetHeights();
2862		};
2863		$.data(this.actElemInput, "runner_chghook", changeHook);
2864		$(this.actElemInput).change(changeHook);
2865	}
2866};
2867
2868// Removes event handler that monitors changes.
2869// Note: Calling more than once will have no effect.
2870FieldCondition.prototype.detachRunner = function () {
2871	var changeHook = $.data(this.actElemInput, "runner_chghook");
2872
2873	if (changeHook) {
2874		$(this.actElemInput).unbind('change', changeHook);
2875		$.removeData(this.actElemInput, "runner_chghook");
2876	}
2877};
2878
2879FieldCondition.prototype.checkDateCommon = function (thisValue, compValue) {
2880	var defaultDate = '1/1/70';
2881	var defualtDateObj = new Date(defaultDate);
2882
2883	var compArr = compValue.split(',');
2884	var valueArr = thisValue.split(',');
2885
2886	var hasTimeOfDayStart = false;
2887	var hasTimeOfDayEnd = false;
2888
2889	var compareStartDate;
2890	var compareEndDate;
2891
2892	if (compArr[0] == '') {
2893		compareStartDate = new Date(defaultDate + ' ' + compArr[2]);
2894	}
2895	else {
2896		compareStartDate = new Date(compArr[0] + ' ' + compArr[2]);
2897	}
2898
2899	if (compArr[1] == '') {
2900		compareEndDate = new Date(defaultDate + ' ' + compArr[3]);
2901	}
2902	else {
2903		compareEndDate = new Date(compArr[1] + ' ' + compArr[3]);
2904	}
2905
2906	var validStartDate = new Date(defaultDate);
2907	var validEndDate = new Date(defaultDate);
2908	var timeOfDayStart = '';
2909	var timeOfDayEnd = '';
2910
2911	if (valueArr.length == 4) {
2912		if (valueArr[0] == '') {
2913			validStartDate = new Date(defaultDate + ' ' + valueArr[2]);
2914		}
2915		else {
2916			validStartDate = new Date(valueArr[0] + ' ' + valueArr[2]);
2917		}
2918
2919		timeOfDayStart = this.getAMPMString(valueArr[2]);
2920
2921		if (timeOfDayStart != '')
2922			hasTimeOfDayStart = true;
2923
2924		if (valueArr[1] == '') {
2925			validEndDate = new Date(defaultDate + ' ' + valueArr[3]);
2926		}
2927		else {
2928			validEndDate = new Date(valueArr[1] + ' ' + valueArr[3]);
2929		}
2930
2931		timeOfDayEnd = this.getAMPMString(valueArr[3]);
2932
2933		if (timeOfDayEnd != '')
2934			hasTimeOfDayEnd = true;
2935	}
2936	else if (valueArr.length == 2) {
2937		timeOfDayStart = this.getAMPMString(valueArr[0]);
2938
2939		if (timeOfDayStart == '') {
2940			if (valueArr[0] != '') {
2941				validStartDate = new Date(valueArr[0]);
2942				hasTimeOfDayStart = true;
2943			}
2944		}
2945		else {
2946			validStartDate = new Date(defaultDate + ' ' + valueArr[0]);
2947			hasTimeOfDayStart = true;
2948		}
2949
2950		timeOfDayEnd = this.getAMPMString(valueArr[1]);
2951
2952		if (timeOfDayEnd == '') {
2953			if (valueArr[1] != '') {
2954				validEndDate = new Date(valueArr[1]);
2955				hasTimeOfDayEnd = true;
2956			}
2957		}
2958		else {
2959			validEndDate = new Date(defaultDate + ' ' + valueArr[1]);
2960			hasTimeOfDayEnd = true;
2961		}
2962	}
2963
2964	return {
2965		validStartDate: validStartDate,
2966		compareStartDate: compareStartDate,
2967		compareEndDate: compareEndDate,
2968		hasTimeOfDayStart: hasTimeOfDayStart,
2969		validEndDate: validEndDate,
2970		hasTimeOfDayEnd: hasTimeOfDayEnd
2971	};
2972};
2973
2974FieldCondition.prototype.checkDateBetween = function (thisValue, compValue) {
2975	var checkDateCommonData = this.checkDateCommon(thisValue, compValue);
2976
2977	return (checkDateCommonData.validStartDate.getTime() >= checkDateCommonData.compareStartDate.getTime() && checkDateCommonData.validStartDate.getTime() <= checkDateCommonData.compareEndDate.getTime() && checkDateCommonData.hasTimeOfDayStart)
2978		&& (checkDateCommonData.validEndDate.getTime() <= checkDateCommonData.compareEndDate.getTime() && checkDateCommonData.validEndDate.getTime() >= checkDateCommonData.compareStartDate.getTime() && checkDateCommonData.hasTimeOfDayEnd);
2979};
2980
2981FieldCondition.prototype.checkDateEqualSpan = function (thisValue, compValue) {
2982	var checkDateCommonData = this.checkDateCommon(thisValue, compValue);
2983
2984	return (checkDateCommonData.validStartDate.getTime() == checkDateCommonData.compareStartDate.getTime() && checkDateCommonData.hasTimeOfDayStart)
2985		&& (checkDateCommonData.validEndDate.getTime() == checkDateCommonData.compareEndDate.getTime() && checkDateCommonData.hasTimeOfDayEnd);
2986};
2987
2988FieldCondition.prototype.checkDateEqualTo = function (thisValue, compValue) {
2989	var defaultDate = '1/1/70';
2990	var defualtDateObj = new Date(defaultDate);
2991
2992	var compArr = compValue.split(',');
2993	var valueArr = thisValue.split(',');
2994
2995	var compareDate;
2996
2997	var hasTimeOfDay = false;
2998
2999	if (compArr[0] == '') {
3000		compareDate = new Date(defaultDate + ' ' + compArr[2]);
3001	}
3002	else {
3003		compareDate = new Date(compArr[0] + ' ' + compArr[2]);
3004	}
3005
3006	var validDate = new Date(defaultDate);
3007	var timeOfDay = '';
3008
3009	if (valueArr.length == 1) {
3010		timeOfDay = this.getAMPMString(valueArr[0]);
3011
3012		if (timeOfDay == '') {
3013			if (valueArr[0] != '') {
3014				validDate = new Date(valueArr[0]);
3015				hasTimeOfDay = true;
3016			}
3017		}
3018		else {
3019			hasTimeOfDay = true;
3020			validDate = new Date(valueArr[0]);
3021		}
3022	}
3023	else if (valueArr.length == 2) {
3024		timeOfDay = this.getAMPMString(valueArr[1]);
3025
3026		if (timeOfDay != '')
3027			hasTimeOfDay = true;
3028
3029		if (valueArr[0] != '') {
3030			validDate = new Date((valueArr[0] + ' ' + valueArr[1] + ' ').replace(/\-/g, '/'));
3031		}
3032		else {
3033			validDate = new Date((defaultDate + ' ' + valueArr[0] + ' ').replace(/\-/g, '/'));
3034		}
3035	}
3036
3037	return validDate.getTime() == compareDate.getTime() && hasTimeOfDay;
3038};
3039
3040FieldCondition.prototype.getAMPMString = function (time) {
3041	var amIndex = time.indexOf('AM');
3042	var pmIndex = time.indexOf('PM');
3043
3044	var timeOfDay = '';
3045
3046	// First see if the time is military time... if so we need to convert it to AM/PM so the rest
3047	// of this function will return the proper value.
3048
3049	if (amIndex === -1 && pmIndex === -1) {
3050		time = militaryTimeToStandard(time);
3051		amIndex = time.indexOf('AM');
3052		pmIndex = time.indexOf('PM');
3053	}
3054
3055	if (amIndex != -1) {
3056		timeOfDay = time.substring(amIndex).replace(" ", "");
3057	}
3058	else if (pmIndex != -1) {
3059		timeOfDay = time.substring(pmIndex).replace(" ", "");
3060	}
3061
3062	return timeOfDay;
3063};
3064
3065function militaryTimeToStandard(militaryTime) {
3066	var colonIndex = militaryTime.indexOf(':');
3067	var hours = '';
3068	var min = '';
3069
3070	if (colonIndex === -1) {
3071		hours = militaryTime.substring(0, 2);
3072		min = militaryTime.substring(2, 4);
3073	} else {
3074		var tokens = militaryTime.split(':');
3075		hours = tokens[0];
3076		min = tokens[1];
3077	}
3078
3079	if (hours < 12) {
3080		ampm = 'AM';
3081	} else {
3082		hours = hours - 12;
3083		ampm = 'PM';
3084	}
3085
3086	return parseInt(hours) + ':' + ('00' + min).slice('-2') + ' ' + ampm; ß
3087}
3088
3089
3090////////// FieldConditions Class //////////
3091
3092// Creates instance of FieldConditions class.
3093// * elemInput - Reference to DOM element of field with condition. May be a DOM element or string containing ID. May also be array of DOM elements or IDs. Multiple elements must share same parent.
3094// * id - The ID of the field with the condition.
3095// * fieldType - The field type of the field with the condition.
3096// * isInternal - Whether or not this condition is for internal-only fields.
3097// * condList - List (array) of zero or more condition clauses for the field.
3098// * validators - Validator dictionary.
3099function FieldConditions(options, validators) {
3100	if (options.elemInput == null)
3101		throw new Error.argNull("options.elemInput");
3102	else if (options.id == null)
3103		throw new Error.argNull("id");
3104	else if (options.fieldType == null)
3105		throw new Error.argNull("options.fieldType");
3106	else if (options.condList == null)
3107		throw new Error.argNull("options.condList");
3108	else if (validators == null)
3109		throw new Error.argNull("validators");
3110
3111	this.elemInputIsArray = $.isArray(options.elemInput);
3112
3113	// Process elemInput argument.
3114	if (this.elemInputIsArray) {
3115		for (var i = 0, len = options.elemInput.length; i < len; i++) {
3116			if (typeof (options.elemInput[i]) == "string")
3117				options.elemInput[i] = document.getElementById(options.elemInput[i]);
3118		}
3119
3120		if (options.elemInput.length > 0 && options.elemInput[0]) {
3121			this.elemContainer = options.elemInput[0].closest('.formFieldContainer');
3122			this.elemInput = options.elemInput;
3123		}
3124	}
3125	else {
3126		if (typeof (options.elemInput) == "string")
3127			options.elemInput = document.getElementById(options.elemInput);
3128
3129		if (options.elemInput) {
3130			this.elemContainer = options.elemInput.closest('.formFieldContainer');
3131			this.elemInput = options.elemInput;
3132		}
3133	}
3134
3135	this.validators = validators;
3136	this.elemReq = document.getElementById('r_' + options.id);
3137	this.$elemContainer = $(this.elemContainer);
3138	this.$elemReq = $(this.elemReq);
3139	this.fieldType = options.fieldType;
3140	this.id = options.id;
3141	this.isInternal = options.isInternal;
3142	this.conditions = FieldCondition.createMulti(this, options.condList);
3143}
3144
3145// Static. Creates a single conditions object from an options object.
3146FieldConditions.createSingle = function (options, validators) {
3147	if (options == null)
3148		throw new Error.argNull("options");
3149	else if (validators == null)
3150		throw new Error.argNull("validators");
3151
3152	return new FieldConditions(
3153		options,
3154		validators);
3155};
3156
3157// Static. Creates dictionary of conditions objects from array of option objects.
3158FieldConditions.createMulti = function (optionsArray, validators) {
3159	if (optionsArray == null)
3160		throw new Error.argNull("optionsArray");
3161	else if (validators == null)
3162		throw new Error.argNull("validators");
3163
3164	var ret = { keys: [] };
3165	var key = null;
3166
3167	for (var i = 0, len = optionsArray.length; i < len; i++) {
3168		if (optionsArray[i].id != null) {
3169			key = optionsArray[i].id;
3170			ret[key] = FieldConditions.createSingle(optionsArray[i], validators);
3171			ret.keys.push(key);
3172		}
3173	}
3174
3175	return ret;
3176};
3177
3178// Attachs event handler to field to monitor changes.
3179// * condRunner - FieldConditionsRunner instance to attach.
3180// Note: Calling more than once will have no effect.
3181FieldConditions.prototype.attachRunner = function (condRunner) {
3182	if (condRunner == null)
3183		throw new Error.argNull("condRunner");
3184
3185	for (var i = 0, len = this.conditions.length; i < len; i++)
3186		this.conditions[i].attachRunner(condRunner);
3187};
3188
3189// Removes event handler that monitors changes.
3190// Note: Calling more than once will have no effect.
3191FieldConditions.prototype.detachRunner = function () {
3192	for (var i = 0, len = this.conditions.length; i < len; i++)
3193		this.conditions[i].detachRunner();
3194};
3195
3196////////// FieldConditionsRunner Class ////
3197
3198// Creates new instance of conditions runners for the field conditions objects provided.
3199// * allFieldConditions - Array of FieldConditions objects to execute checks for.
3200// * doneCallback - Method executed when run() completes. Recieves log information as argument.
3201// * autoAttach - Determines if allFieldConditions are automatically attached to this instance by the constructor. If null/unspecified, treated as true.
3202// * runInternal - Set to true to execute internal-only fields.
3203function FieldConditionsRunner(allFieldConditions, doneCallback, autoAttach, runInternal) {
3204	if (allFieldConditions == null)
3205		throw new Error.argNull("allFieldConditions");
3206	else if (doneCallback == null)
3207		throw new Error.argNull("doneCallback");
3208
3209	this.fieldConditions = allFieldConditions;
3210	this.doneCallback = doneCallback;
3211	this.runInternal = runInternal;
3212
3213	if (autoAttach == null || autoAttach)
3214		this.attachConditions();
3215}
3216
3217// Static. Internal. Creates static information object for state tracking during execution.
3218FieldConditionsRunner.createFieldStateInfo = function () {
3219	var ret = {};
3220
3221	ret[ConditionActions.None] = ConditionRunnerActResult.None;
3222	ret[ConditionActions.Show] = ConditionRunnerActResult.None;
3223	ret[ConditionActions.Hide] = ConditionRunnerActResult.None;
3224	ret[ConditionActions.Require] = ConditionRunnerActResult.None;
3225	ret[ConditionActions.RedirectTo] = ConditionRunnerActResult.None;
3226
3227	return ret;
3228};
3229
3230// Attaches to FieldConditions/FieldCondition objects that runner will use.
3231FieldConditionsRunner.prototype.attachConditions = function () {
3232	for (var i = 0, iLen = this.fieldConditions.keys.length; i < iLen; i++)
3233		this.fieldConditions[this.fieldConditions.keys[i]].attachRunner(this);
3234};
3235
3236// Detaches to FieldConditions/FieldCondition objects that runner may have used.
3237FieldConditionsRunner.prototype.detachConditions = function () {
3238	for (var i = 0, iLen = this.fieldConditions.keys.length; i < iLen; i++)
3239		this.fieldConditions[this.fieldConditions.keys[i]].detachRunner(this);
3240};
3241
3242// Internal. Cleans up runner for use again.
3243FieldConditionsRunner.prototype.cleanup = function () {
3244	if (this.fieldConditionResults != null) {
3245		delete this.fieldConditionResults;
3246		delete this.fieldConditionLog;
3247	}
3248};
3249
3250// Internal. Called by run() to log result for each condition.
3251FieldConditionsRunner.prototype.log = function (id, condIndex, actType, result, isMet, needRestart) {
3252	if (condRunnerHideLogDupes && result == ConditionRunnerActResult.SkipDuplicate)
3253		return;
3254
3255	this.fieldConditionLog.push({
3256		id: id,
3257		condIndex: condIndex,
3258		actType: actType,
3259		result: result,
3260		isMet: isMet,
3261		needRestart: needRestart
3262	});
3263};
3264
3265// Internal. Sets whether or not the condition engine is executing.
3266FieldConditionsRunner.prototype.setRunning = function (value) {
3267	if (arguments.length == 0)
3268		this.isRunning = true;
3269	else
3270		this.isRunning = value;
3271};
3272
3273// Gets whether or not the condition engine is executing.
3274FieldConditionsRunner.prototype.getRunning = function () {
3275	return this.isRunning;
3276};
3277
3278// Internal. Tells condition execution task to reset cycle (done whenever something changes).
3279FieldConditionsRunner.prototype.setRestart = function (value) {
3280	if (arguments == null || arguments.length == 0)
3281		this.needRestart = true;
3282	else
3283		this.needRestart = value;
3284};
3285
3286// Internal. Gets whether or not the runner needs to restart.
3287FieldConditionsRunner.prototype.getRestart = function () {
3288	return this.needRestart;
3289};
3290
3291// Launches execution of conditions.
3292// * fromEvent - Should be set to true when triggerd from DOM events.
3293// NOTE: fromEvent may be a race condition but will be left for now while debugging (to simplify logs).
3294FieldConditionsRunner.prototype.run = function (fromEvent) {
3295	if (this.getRunning() && !fromEvent)
3296		this.setRestart();
3297	else {
3298		this.setRunning();
3299
3300		this.cleanup();
3301
3302		this.runTask();
3303
3304		this.doneCallback(this.fieldConditionLog);
3305
3306		this.setRunning(false);
3307	}
3308};
3309
3310// Internal. Executes conditions. Should not be called while already running, so run() has sync mechanism for this.
3311// * runInternal - If true, conditions for internal conditions will be ran.
3312FieldConditionsRunner.prototype.runTask = function (runInternal) {
3313	var needRestart = true;
3314
3315	// Prepare objects for execution.
3316	this.fieldConditionLog = [];
3317	this.fieldConditionResults = [];
3318	this.setRedirectUrl = false;
3319
3320	// Populate state information.
3321	var condCondList = this.fieldConditions;
3322	var condListInfo = null;
3323	var condList = null;
3324
3325	for (var i = 0, iLen = condCondList.keys.length; i < iLen; i++)
3326		this.fieldConditionResults[condCondList[condCondList.keys[i]].id] = FieldConditionsRunner.createFieldStateInfo();
3327
3328	// Number of restart actions (tracked to eventually kill infinite loops that should not happen).
3329	var numRestarts = 0;
3330
3331	// Start/restart actions.
3332	while (needRestart && (++numRestarts < 65535)) {
3333		needRestart = false;
3334		this.setRestart(needRestart);
3335
3336		for (var i = 0, iLen = condCondList.keys.length; i < iLen && !needRestart; i++) {
3337			condListInfo = condCondList[condCondList.keys[i]];
3338
3339			// If we are on the front-end, we don't want to have anything to do with back-end (internal only)
3340			// conditions, they will cause javascript errors.
3341			if (!this.runInternal && condListInfo.isInternal == true)
3342				continue;
3343
3344			if (condListInfo.isInternal == false && document.URL.indexOf("Admin") > -1 && document.URL.indexOf("Submissions") > -1)
3345				continue;
3346
3347			condList = condListInfo.conditions;
3348
3349			for (var j = 0, jLen = condList.length; j < jLen && !needRestart; j++) {
3350				var cond = condList[j];
3351				var results = this.fieldConditionResults[condListInfo.id];
3352				var logState = ConditionRunnerActResult.None;
3353
3354				// Determine whether or not condition is met.
3355				var isMet = cond.check(false);
3356
3357				// This is because the effective action for a failed explicit Show is an implicit Hide (and vice versa).
3358				var effectiveActType = cond.actType;
3359
3360				// Determine if action is contradictory or duplicate and skip UI changes if so.
3361				switch (effectiveActType) {
3362					case ConditionActions.Show:
3363						// Show can collide with hide.
3364						var resultsHide = results[ConditionActions.Hide];
3365
3366						if (resultsHide == ConditionRunnerActResult.SuccessExplicit || (resultsHide == ConditionRunnerActResult.SuccessImplicit && !isMet))
3367							logState = ConditionRunnerActResult.SkipContradiction;
3368
3369						break;
3370					case ConditionActions.Hide:
3371						// Hide can collide with show.
3372						var resultsShow = results[ConditionActions.Show];
3373
3374						if (resultsShow == ConditionRunnerActResult.SuccessExplicit || (resultsShow == ConditionRunnerActResult.SuccessImplicit && !isMet))
3375							logState = ConditionRunnerActResult.SkipContradiction;
3376
3377						break;
3378					case ConditionActions.RedirectTo:
3379						// Redirects work differently since they span all fields. Extra contradiction detection needed.
3380						if (this.setRedirectUrl)
3381							logState = ConditionRunnerActResult.SkipContradiction;
3382						else if (isMet)
3383							this.setRedirectUrl = true;
3384						break;
3385				}
3386
3387				if (isMet && results[effectiveActType] == ConditionRunnerActResult.SuccessExplicit)
3388					logState = ConditionRunnerActResult.SkipDuplicate;
3389				else if (!isMet && results[effectiveActType] == ConditionRunnerActResult.SuccessExplicit)
3390					logState = ConditionRunnerActResult.SkipContradiction;
3391				else if (!isMet && results[effectiveActType] == ConditionRunnerActResult.SuccessImplicit)
3392					logState = ConditionRunnerActResult.SkipDuplicate;
3393
3394				if (logState == ConditionRunnerActResult.None) {
3395					// Determine log result.
3396					logState = isMet ? ConditionRunnerActResult.SuccessExplicit : ConditionRunnerActResult.SuccessImplicit;
3397
3398					// Update running state info.
3399					results[effectiveActType] = logState;
3400
3401					// Update form UI.
3402					cond.doAction(isMet);
3403
3404					// Restart task.
3405					this.setRestart();
3406					needRestart = true;
3407				}
3408
3409				// Log result.
3410				this.log(condListInfo.id, j, cond.actType, logState, isMet, needRestart);
3411
3412				// Some other action could cause this to get set.
3413				if (this.getRestart())
3414					needRestart = true;
3415			}
3416		}
3417	}
3418
3419	if (numRestarts >= 65535)
3420		console[console.warn ? "warn" : "log"]("Infinite Loop (heuristic-detected) in FieldConditionsRunner.runTask()");
3421};
3422;
3423// This file contains javascript functions for the "External Integration" field type.
3424// REQUIREMENTS:
3425//		FieldSetDesigner.js
3426
3427// These values must match the values provided in CivicPlus.Entities.Modules.FormCenter.Enums.ExternalIntegrationCommandType
3428var ExternalIntegrationCommandType = {
3429	XMLCommand: 1,
3430	EchoCommand: 2
3431};
3432
3433// Closure containing the client-side functionality for the External Integration field type.
3434// * externalIntegrationClass - The name of the CSS class that is used to identify external integration buttons.
3435function ExternalIntegration(externalIntegrationClassname, fieldSetDesigner) {
3436	this.cssClassname = externalIntegrationClassname;
3437	this.fieldSetDesigner = fieldSetDesigner;
3438
3439	this.hookEvents = function () {
3440		var my = this;
3441		if (my.cssClassname == null)
3442			throw 'No external integration button CSS class name has been specified.'
3443
3444		$('.' + this.cssClassname).click(function (event) {
3445			var fieldID = null;
3446			fieldID = event.target.id;
3447			my.sendRequest(fieldID);
3448		});
3449	};
3450
3451	this.sendRequest = function (fieldID) {
3452		var params = this.getFormData();
3453        var formID = $('#Item_FormID').val();
3454        var intFieldID = fieldID.replace('e_', '');
3455
3456		var my = this;
3457		var sendData = {
3458		    id: formID,
3459		    fieldID: intFieldID,
3460			parameters: JSON.stringify(params)
3461		};
3462
3463		$.ajax({
3464			type: 'post',
3465			url: '/FormCenter/ExecuteExternalIntegrationCommand',
3466			data: sendData,
3467			success: function (data) { my.updateFormData(data, my); },
3468			error: function (xhr, status, error) { alert('An error occurred while sending the request.'); },
3469		    beforeSend: function () {
3470		        ajaxPostBackStart('Loading');
3471		    },
3472	        complete: function () {
3473		        ajaxPostBackEnd();
3474		    }
3475		});
3476	};
3477
3478	// This function takes the values from the JSON result and sets the appropriate
3479	// form field values.
3480	this.updateFormData = function (responseFromController, externalIntegrationObject) {
3481
3482		if (responseFromController.error) {
3483			alert('An error occurred: ' + responseFromController.errorMessage);
3484			return;
3485		}
3486
3487		for (var i = 0, len = responseFromController.length; i < len; i++) {
3488			var param = responseFromController[i];
3489			switch (responseFromController[i].Type) {
3490				case FieldTypes.ShortAnswer:
3491					externalIntegrationObject.updateShortAnswerField(param);
3492					break;
3493				case FieldTypes.LongAnswer:
3494					externalIntegrationObject.updateLongAnswerField(param);
3495					break;
3496				case FieldTypes.Checkboxes:
3497					externalIntegrationObject.updateCheckboxField(param);
3498					break;
3499				case FieldTypes.Dropdown:
3500					externalIntegrationObject.updateDropdownField(param);
3501					break;
3502				case FieldTypes.Password:
3503					externalIntegrationObject.updatePasswordField(param);
3504					break;
3505				case FieldTypes.RadioButtons:
3506					externalIntegrationObject.updateRadioField(param);
3507					break;
3508			    case FieldTypes.DateTime:
3509			        externalIntegrationObject.updateDateField(param);
3510			        break;
3511			}
3512		}
3513	}
3514
3515	this.getFormData = function () {
3516		var params = [];
3517
3518		this.appendShortAnswerFields(params);
3519		this.appendCheckboxFields(params);
3520		this.appendRadioFields(params);
3521		this.appendDropdowns(params);
3522		this.appendTextAreaFields(params);
3523		this.appendPasswordFields(params);
3524
3525		return params;
3526	};
3527
3528	this.createFieldValue = function (fieldID, type, value, externalName) {
3529		return { ID: fieldID, Type: type, Value: value, ExternalName: externalName};
3530	};
3531
3532	this.appendShortAnswerFields = function (params) {
3533		var my = this;
3534		$('input[id^="e_"][type="text"]').each(function (i) {
3535			var element = $(this);
3536			params.push(my.createFieldValue(element.attr('id'), FieldTypes.ShortAnswer, element.val(), my.externalSubmissionName(element)));
3537		});
3538	};
3539
3540	this.externalSubmissionName = function($element) {
3541	    return $element.parents('*[data-external-submission-name]').attr('data-external-submission-name');
3542	};
3543
3544	this.updateShortAnswerField = function (param) {
3545		var id = param.ID;
3546		$('#' + param.ID).val(param.Value);
3547	}
3548
3549	this.appendCheckboxFields = function (params) {
3550		var my = this;
3551		$('input[id^="e_"][type="checkbox"]').each(function (index) {
3552			var item = $(this);
3553			var value = item.attr('value');
3554			var checked = false;
3555			if (item.is(':checked')) {
3556			    checked = true;
3557			}
3558			var fieldValue = my.createFieldValue(item.attr('id'), FieldTypes.Checkboxes, value, my.externalSubmissionName(item));
3559			fieldValue.Checked = checked;
3560			params.push(fieldValue);
3561		});
3562	};
3563
3564	this.updateCheckboxField = function (param) {
3565		var id = param.ID;
3566		if (param.Checked == true)
3567			$('#' + param.ID).prop('checked', true);
3568		else
3569			$('#' + param.ID).prop('checked', false);
3570	};
3571
3572	this.appendRadioFields = function (params) {
3573		var my = this;
3574		$('input[id^="e_"][type="radio"]').each(function (index) {
3575			var item = $(this);
3576			var value = item.attr('value');
3577			var checked = false;
3578			if (item.is(':checked')) {
3579			    checked = true;
3580			}
3581			var fieldValue = my.createFieldValue(item.attr('id'), FieldTypes.RadioButtons, value, my.externalSubmissionName(item));
3582			fieldValue.Checked = checked;
3583
3584			params.push(fieldValue);
3585		});
3586	};
3587
3588	this.updateRadioField = function (param) {
3589	    var id = param.ID;
3590	    var value = param.Value;
3591	    var button = $('input[id^="' + id + '"][value="' + value + '"]');
3592	    button.prop('checked', true);
3593	};
3594
3595	this.appendDropdowns = function (params) {
3596		var my = this;
3597		$('select[id^="e_"]').each(function (index) {
3598			var item = $(this);
3599			params.push(my.createFieldValue(item.attr('id'), FieldTypes.Dropdown, item.val(), my.externalSubmissionName(item)));
3600		});
3601	};
3602
3603	this.updateDropdownField = function (param) {
3604		$('#' + param.ID).val(param.Value);
3605	}
3606
3607	this.appendTextAreaFields = function (params) {
3608		var my = this;
3609		$('textarea[id^="e_"]').each(function (index) {
3610			var element = $(this);
3611
3612			if (element.closest('li.LongAnswer').length > 0) {
3613				params.push(my.createFieldValue(element.attr('id'), FieldTypes.LongAnswer, element.text(), my.externalSubmissionName(element)));
3614			}
3615		});
3616	};
3617
3618	this.updateLongAnswerField = function (param) {
3619		$('#' + param.ID).text(param.Value);
3620	}
3621
3622	this.appendPasswordFields = function (params) {
3623		var my = this;
3624		$('input[id^="e_"][type="password"').each(function (i) {
3625			var element = $(this);
3626			params.push(my.createFieldValue(element.attr('id'), FieldTypes.Password, element.val(), my.externalSubmissionName(element)));
3627		});
3628	}
3629
3630	this.updatePasswordField = function (param) {
3631		// We don't want to update password information with values returned from the remote service.
3632		return;
3633	}
3634
3635	this.updateDateField = function (param) {
3636	    var my = this;
3637	    var isSpan = (param.Value.indexOf(',') >= 0);
3638
3639	    var dateID = param.ID + '_date';
3640	    var timeID = param.ID + '_time';
3641	    var endDateID = param.ID + '_dateSpan';
3642	    var endTimeID = param.ID + '_timeSpan';
3643        
3644	    var updateDate = function (selector, val) {
3645	        var datePicker = $('#' + selector);
3646	        if (datePicker.length == 0)
3647	            return;
3648
3649	        datePicker.data('tDatePicker').value(val);
3650	    };
3651
3652	    var updateTime = function (selector, val) {
3653	        var timePicker = $('#' + selector);
3654	        if (timePicker.length == 0)
3655	            return;
3656	        timePicker.data('tTimePicker').value(val);
3657	    };
3658
3659	    if (isSpan) {
3660	        var dateArray = param.Value.split(',');
3661	        var startDate = new Date(dateArray[0]);
3662	        var endDate = new Date(dateArray[1]);
3663            
3664	        updateDate(dateID, startDate);
3665	        updateTime(timeID, startDate);
3666
3667	        updateDate(endDateID, endDate);
3668	        updateTime(endTimeID, endDate);
3669	    } else {
3670	        var startDate = new Date(param.Value);
3671	        updateDate(dateID, startDate);
3672	        updateTime(timeID, startDate);
3673	    }
3674	}
3675};
3676
3677// Calls subroutines used to initialize the ExternalIntegration javascript object.
3678ExternalIntegration.prototype.initialize = function () {
3679	this.hookEvents();
3680};
3681
3682var CP_DynamicForm_ExternalSubmissionFE = function($) {
3683
3684	var self = this;
3685
3686
3687	self.getExternalSubmissionData = function() {
3688		var $fieldContainers = $('.formFieldContainer');
3689		var data = {};
3690		$fieldContainers.each(function (index) {
3691			var $container = $(this);
3692			var externalSubmissionName = self.getExternalSubmissionName($container);
3693			var singleFieldData = self.getSingleFieldData($container);
3694			if (singleFieldData != null) {
3695				data[externalSubmissionName] = self.getSingleFieldData($container);
3696			}
3697		});
3698		return data;
3699	};
3700
3701	self.getExternalSubmissionName = function($container) {
3702		return $container.attr('data-external-submission-name');
3703	};
3704
3705	self.getSingleFieldData = function($container) {
3706		var self = this;
3707		var result = null;
3708		if ($container.hasClass('ShortAnswer')) {
3709			result = self.submissionDataShortAnswer($container);
3710		} else if ($container.hasClass('LongAnswer')) {
3711			result = self.submissionDataLongAnswer($container);
3712		} else if ($container.hasClass('Checkboxes')) {
3713			result = self.submissionDataCheckboxes($container);
3714		} else if ($container.hasClass('Dropdown')) {
3715			result = self.submissionDataDropdown($container);
3716		} else if ($container.hasClass('RadioButtons')) {
3717			result = self.submissionDataRadioButtons($container);
3718		} else if ($container.hasClass('ReplyEmail')) {
3719			result = self.submissionDataReplyEmail($container);
3720		} else if ($container.hasClass('DateTime')) {
3721			result = self.submissionDataDateTime($container);
3722		} else if ($container.hasClass('DateTimeSpan')) {
3723			result = self.submissionDataDateTimeSpan($container);
3724		} else if ($container.hasClass('Password')) {
3725			result = self.submissionDataPassword($container);
3726		}
3727
3728		return result;
3729	};
3730
3731	//
3732	// There needs to be one function for each type of field that will be passed to 
3733	// an external submission service.
3734	//
3735
3736	self.submissionDataShortAnswer = function($container) {
3737		return $('input[id^=e_]', $container).val();
3738	};
3739
3740	self.submissionDataLongAnswer = function($container) {
3741		return $('textarea', $container).html();
3742	};
3743
3744	self.submissionDataPassword = function($container) {
3745		return $('input[id^=e_]', $container).val();
3746	};
3747
3748	self.submissionDataCheckboxes = function($container) {
3749		var result = [];
3750		var $checkedItems = $('input[type=checkbox]:checked', $container);
3751		$checkedItems.each(function (index) {
3752			result.push($(this).attr('Value'));
3753		});
3754		return result.join();
3755	};
3756
3757	self.submissionDataDropdown = function($container) {
3758		return $('select option:selected').val();
3759	};
3760
3761	self.submissionDataRadioButtons = function($container) {
3762		return $('input:radio:checked', $container).val();
3763	};
3764
3765	self.submissionDataReplyEmail = function($container) {
3766		return $('input[id^=e_]', $container).val();
3767	};
3768
3769	self.isDateTimeValueEmpty = function(val) {
3770		// The telerik controls sometimes have just "0" if the user does not
3771		// enter a value, so this function checks for both an empty value and for "0"
3772		if (val == null || val == '' || val == '0')
3773			return true;
3774		else
3775			return false;
3776	};
3777
3778	self.submissionDataDateTime = function($container) {
3779		var $dateDiv = $('div.date', $container).not('.time')[0];
3780		var $timeDiv = $('div.time', $container)[0];
3781
3782		var date = $('input', $dateDiv).val();
3783		var time = $('input', $timeDiv).val();
3784
3785		return formatDateTime(date, time);
3786	};
3787
3788	self.formatDateTime = function(date, time) {
3789		var dateEmpty = isDateTimeValueEmpty(date);
3790		var timeEmpty = isDateTimeValueEmpty(time);
3791
3792		if (dateEmpty && timeEmpty)
3793			return '';
3794		else if (!dateEmpty && timeEmpty)
3795			return date;
3796		else if (dateEmpty && !timeEmpty)
3797			return time;
3798		else
3799			return date + ' ' + time;
3800	}
3801
3802	self.submissionDataDateTimeSpan = function($container) {
3803		var $startDateDiv = $('div.date', $container).not('.time')[0];
3804		var $startTimeDiv = $('div.date.time', $container)[0];
3805		var startDate = $('input', $startDateDiv).val();
3806		var startTime = $('input', $startTimeDiv).val();
3807
3808		var $endDateDiv = $('div.date', $container).not('.time')[1];
3809		var $endTimeDiv = $('div.date.time', $container)[1];
3810		var endDate = $('input', $endDateDiv).val();
3811		var endTime = $('input', $endTimeDiv).val();
3812
3813		var startDateTime = formatDateTime(startDate, startTime);
3814		var endDateTime = formatDateTime(endDate, endTime);
3815
3816		if (startDateTime == '' && endDateTime == '')
3817			return '';
3818
3819		return startDateTime + ',' + endDateTime;
3820	};
3821
3822
3823	return self;
3824}(jQuery);
3825
3826
3827var CP_DynamicForm_PrintSubmission = (function () {
3828	self.StatusCodes = {
3829		Loading: 1,
3830		Success: 2,
3831		Spam: 3,
3832		Timeout: 4
3833	};	
3834
3835	return self;
3836})();
3837/// <reference path="../../../../Assets/Scripts/FrontEnd.js" />
3838/// <reference path="../../../../Assets/Scripts/Authentication/PopupBasedAuthentication.js" />
3839/// <reference path="../../../../Assets/Scripts/Store.js" />
3840/// <reference path="../../../../Assets/Scripts/Authentication/Authentication.js" />
3841/// <reference path="../../../../Assets/Scripts/Shared.js" />
3842
3843window.FormCenter = window.FormCenter || {};
3844
3845function SaveProgressClass() {
3846    var url;
3847}
3848
3849if (!window.FormCenter.SaveProgress) {
3850    window.FormCenter.SaveProgress = new SaveProgressClass();
3851}
3852
3853SaveProgressClass.prototype.checkLoggedInStatus = function (event) {
3854    if (event != null) {
3855        event.preventDefault();
3856    }
3857
3858    submitCheckboxHandler();
3859    submitRadioHandler();
3860    submitDateTimeHandler();
3861
3862    if ($('[type="file"]').length > 0) {
3863        alert($('#hdnFileUploadWarning').val());
3864    }
3865
3866    var $form = $(document.aspnetForm);
3867
3868    window.FormCenter.SaveProgress.url = null;
3869
3870    window.FormCenter.SaveProgress.url = $(this).data('redirect-url');
3871
3872    var savedProgressID = $('#hdnSavedProgressID').val();
3873
3874    var postUrl = '/FormCenter/Home/SaveProgress?formID=' + $('#hdnFormID').val();
3875
3876    if (savedProgressID != null) {
3877        postUrl = postUrl + '&savedProgressID=' + savedProgressID;
3878    }
3879
3880    $.ajax({
3881        url: postUrl,
3882        type: 'POST',
3883        contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
3884        data: $(document.aspnetForm).serializeArray(),
3885        success: FormCenter.SaveProgress.savePostCallback,
3886        async: false,
3887        beforeSend: function () {
3888            ajaxPostBackStart('Loading');
3889        },
3890        complete: function () {
3891            ajaxPostBackEnd();
3892        },
3893        error: function (xhr, textStatus, exception) {
3894            alert('Error: ' + xhr.statusText + '\nStatus: ' + xhr.status);
3895        }
3896    });
3897};
3898
3899SaveProgressClass.prototype.savePostCallback = function(response) {
3900    if (response.Successful) {
3901        if (response.LoggedIn) {
3902            if (response.RedirectUrl != null) {
3903                window.FormCenter.SaveProgress.setStorageToShowMessage();
3904
3905                window.location = response.RedirectUrl;
3906            }
3907            else {
3908                alert(response.Message);
3909            }
3910        }
3911        else {
3912            window.FormCenter.SaveProgress.setStorageToShowMessage();
3913            window.FormCenter.SaveProgress.url = window.FormCenter.SaveProgress.url + '?savedProgressKey=' + response.Key;
3914            if (response.IsSamlLoginEnabled) {
3915            	window.location = '/Admin/Saml/LogonRequest?RelayState=' + window.FormCenter.SaveProgress.url.substring(1);
3916            }
3917            else {
3918            	popupSignIn(encodeURI(window.FormCenter.SaveProgress.url), '', FormCenter.SaveProgress.checkLoggedInStatusCallBack);
3919            }
3920        }
3921    }
3922    else {
3923        alert(response.Message);
3924        if (response.hasOwnProperty('FormUnavailable') && response.FormUnavailable)
3925        {
3926            window.location.href = '/FormCenter';
3927        }
3928    }
3929};
3930
3931SaveProgressClass.prototype.setStorageToShowMessage = function () {
3932    $.jStorage.set("showSavedMessage" + $('#hdnFormID').val(), true);
3933};
3934
3935SaveProgressClass.prototype.checkLoggedInStatusCallBack = function () {
3936
3937};
3938
3939SaveProgressClass.prototype.deleteProgress = function (event) {
3940    event.preventDefault();
3941
3942    var postUrl = '/FormCenter/Home/DeleteSaveProgress?savedProgressID=' + $(this).attr('data-progressID');
3943
3944    AJAX(postUrl, 'POST', null, FormCenter.SaveProgress.deleteProgressCallback, true, null, true);
3945};
3946
3947SaveProgressClass.prototype.deleteProgressCallback = function(response) {
3948    if (response.Successful) {
3949        $('#savedProgressTr' + response.SavedProgressID).remove();
3950    }
3951};
3952
3953SaveProgressClass.prototype.init = function () {
3954	if ($.jStorage != null) {
3955		$('#saveFormProgress').unbind().bind({
3956			click: FormCenter.SaveProgress.checkLoggedInStatus
3957		});
3958
3959        $('.modern-button.deleteSavedProgress').unbind().bind({
3960			click: FormCenter.SaveProgress.deleteProgress
3961		});
3962
3963		var storageKey = "showSavedMessage" + $('#hdnFormID').val();
3964
3965		var showSavedMessage = $.jStorage.get(storageKey, false);
3966
3967		if (showSavedMessage && window.location.search.indexOf("savedProgressID") > 0) {
3968			$.jStorage.deleteKey(storageKey);
3969
3970			if (window.location.search.indexOf("savedProgressID=-1") == -1) {
3971				alert($('#hdnSavedProgressMessage').val());
3972			}
3973		}
3974	}
3975};
3976
3977$(document).ready(FormCenter.SaveProgress.init);
3978;
3979window.pageHandleResponsive = true;
3980
3981$.when(window.Pages.rwdReady).done(function () {
3982
3983	toggleClassMedia("maxWidth600px", ".cpForm:media(this-max-width: 600px)");
3984	toggleClassMedia("maxWidth515px", "#FormCenterContent:media(this-max-width: 515px)");
3985	toggleClassMedia("maxWidth485px", "#FormCenterContent:media(this-max-width: 485px)");
3986	toggleClassMedia("maxWidth440px", ".cpForm:media(this-max-width: 440px)");
3987	toggleClassMedia("maxWidth395px", "#FormCenterContent:media(this-max-width: 395px)");
3988	toggleClassMedia("maxWidth380px", ".cpForm:media(this-max-width: 380px)");
3989});
3990

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.