PageSourceSearch

https://cityofanderson.com/-1739875494.js

js cityofanderson.com collected 2026-10-02 10:08:26 UTC 124,916 bytes, 4,135 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;
3423var fb_busy = false;
3424$(document).ready(function () {
3425	if ($('#makeToolbarSignInButtonDisappear').val() == 'True') {
3426		if ($('#loggedOutToolbarSignInButton')) {
3427			$('#loggedOutToolbarSignInButton').hide();
3428			$('#signedOutToolbarMoreInformationButtons').hide();
3429		}
3430	}
3431
3432	var userName;
3433
3434	if (document.layers)
3435		document.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT)
3436
3437	document.onmouseover = hidestatus;
3438	document.onmouseout = hidestatus;
3439
3440	userName = document.getElementById('UserName');
3441	if (userName) {
3442		if (userName.value == '') {
3443			userName.focus();
3444		} else {
3445			document.getElementById('Password').focus();
3446		}
3447	}
3448
3449	if (document.getElementById('fb-root')) {
3450		if (typeof (FB) != "undefined") {
3451			FB.init({
3452				appId: $('#AppID').val(),
3453				cookie: true,
3454				status: true,
3455				oauth: true
3456			});
3457		}
3458		$('.fb-login').click(function (evt) {
3459			var from;
3460			var url;
3461			var anchor;
3462			var signInURL;
3463
3464			if (fb_busy) return;
3465			fb_busy = true;
3466
3467			$('.fb-login').fadeOut(100);
3468			$('.loginBox').fadeOut(100);
3469			$('#login-fb-waiting-text').delay(100).text('Signing in with Facebook...');
3470			$('#login-fb-waiting').delay(100).fadeIn(100);
3471
3472			try {
3473				FB.login(function (response) {
3474					if (response.authResponse) {
3475						var res = HasAcceptedTerms('/MyAccount/HasAcceptedTermsFacebook?access_token=' 
3475+ response.authResponse.accessToken + '&orgName=' + (document.getElementById('Organization') != null ? document.getElementById('Organization').value : ''));
3476						if (res.status != 1) {
3477							alert(res.msg);
3478						} else if (!res.HasAcceptedTerms) {
3479							ShowTerms(function () {
3480								PerformFacebookSignIn(response.authResponse.accessToken);
3481							});
3482						} else {
3483							PerformFacebookSignIn(response.authResponse.accessToken);
3484						}
3485					} else {
3486						// user is not logged in
3487						LoginFailed('Sign in with Facebook cancelled.');
3488					}
3489				}, {
3490					scope: 'email'
3491				});
3492			} catch (e) {
3493
3494			}
3495		});
3496	}
3497
3498	$('.performSignIn').unbind('click').click(function (e) {
3499		performSignIn();
3500	});
3501
3502	$('.forgot').unbind('click').click(function (e) {
3503		var $self = $(this);
3504		var uniqueID = $self.parents('ol.loginBox').find('.UniqueID').val();
3505		var username = $('#UserName' + uniqueID).val();
3506		recover(username);
3507	});
3508});
3509
3510function PerformFacebookSignIn(accessToken) {
3511	// user is logged in and granted permission.
3512	signInURL = '/MyAccount/FacebookSignIn?access_token=' + accessToken;
3513	from = GetQueryStringParameter('from');
3514	var dn = GetQueryStringParameter('dn');
3515	if (dn != "") {
3516		signInURL = signInURL + '&dn=' + dn;
3517	}
3518	if (from != "") {
3519		url = GetQueryStringParameter('url');
3520		anchor = GetQueryStringParameter('anchor');
3521		signInURL = signInURL + '&from=' + from + '&url=' + url + '&anchor=' + anchor;
3522
3523	}
3524
3525	window.location.href = signInURL;
3526}
3527
3528function LoginFailed(message) {
3529	$('#login-fb-waiting-text').fadeOut(250);
3530	$('#login-fb-waiting-text').text(message);
3531	$('#login-fb-waiting-text').fadeIn(250).delay(2000).fadeOut(250);
3532	$('#login-fb-waiting').delay(2250).fadeOut(250);
3533	$('.loginBox').delay(2250).fadeIn(250);
3534	$('.fb-login').delay(2250).fadeIn(250);
3535	fb_busy = false;
3536}
3537
3538function hidestatus() {
3539	window.status = ''
3540	return true
3541}
3542
3543function performSignIn() {
3544	var res = HasAcceptedTerms('/MyAccount/HasAcceptedTerms?userName=' + document.getElementById('UserName').value + '&orgName=' + (document.getElementById('Organization') != null ? document.getElementById('Organization').value : ''));
3545	if (res.status != 1) {
3546		alert(res.msg);
3547	} else if (!res.HasAcceptedTerms) {
3548		ShowTerms(function () {
3549			if (window.chrome !== null && window.chrome !== undefined && window.navigator.vendor === "Google Inc.") {
3550				setTimeout(function () { //issue with chrome where the form submit doesn't respect the form's action. SetTimeout is a workaround.
3551					$('#aspnetForm:first').submit();
3552				}, 0);
3553			} else {
3554				$('#aspnetForm:first').submit();
3555			}
3556
3557		});
3558	} else {
3559		//This call is necessary here since when we do programatic submits, it does not remove the placeholder and the submit handler automatically. Refer to removePlaceHolder() in GlobalJSFunctionDetail.js for detailed comment.
3560		removePlaceHolders();
3561		setDaysSinceLastLoginCookie();
3562		if (window.chrome !== null && window.chrome !== undefined && window.navigator.vendor === "Google Inc.") {
3563			setTimeout(function () { //issue with chrome where the form submit doesn't respect the form's action. SetTimeout is a workaround.
3564				$('#aspnetForm:first').submit();
3565			}, 0);
3566		} else {
3567			$('#aspnetForm:first').submit();
3568		}
3569	}
3570}
3571
3572function signInOnEnter(ev) {
3573	ev = (window.event ? window.event : ev);
3574
3575	if (ev.keyCode == 10 || ev.keyCode == 13)
3576		performSignIn();
3577}
3578
3579function VerifyUserOnEnter(ev) {
3580	ev = (window.event ? window.event : ev);
3581
3582	if (ev.keyCode == 10 || ev.keyCode == 13)
3583		VerifyEditUser();
3584}
3585
3586function VerifyEditUser(isNew) {
3587	var alertMsg = "";
3588	var errString = 'The form can not be submitted due to the following error(s):\n';
3589	errString += "-----------------------------------------------------------------------\n\n";
3590	var doSubmit = true;
3591
3592	txtPassword = TrimString(document.getElementById('Password').value);
3593	txtConfirmPassword = TrimString(document.getElementById('ConfirmPassword').value);
3594
3595	if (FieldIsEmpty(document.getElementById('UserName').value)) {
3596		doSubmit = false;
3597		alertMsg += "Your email cannot be blank.\n";
3598	}
3599
3600	if (FieldIsEmpty(document.getElementById('FirstName').value)) {
3601		doSubmit = false;
3602		alertMsg += "Your first name cannot be blank.\n";
3603	}
3604
3605	if (FieldIsEmpty(document.getElementById('LastName').value)) {
3606		doSubmit = false;
3607		alertMsg += "Your last name cannot be blank.\n";
3608	}
3609
3610	if (txtPassword != txtConfirmPassword) {
3611		doSubmit = false;
3612		alertMsg += "Passwords do not match.\n";
3613	}
3614
3615	if ((txtPassword.length > 0) && (txtPassword.length < 5)) {
3616		doSubmit = false;
3617		alertMsg += "Password needs to be 5 characters or longer.\n";
3618	}
3619
3620	if (isNew) {
3621		if (FieldIsEmpty(document.getElementById('Password').value)) {
3622			doSubmit = false;
3623			alertMsg += "Your password cannot be blank.\n";
3624		}
3625
3626		if (!$('#HasAcceptedTerms').is(':checked')) {
3627			doSubmit = false;
3628			alertMsg += "You must agree to the policies, terms and conditions.\n";
3629		}
3630	}
3631
3632	if (alertMsg.length > 0) {
3633		errString += alertMsg;
3634		errString += "\n-----------------------------------------------------------------------\n";
3635		errString += "Please correct them and re-submit.";
3636		alert(errString)
3637	}
3638
3639	if (doSubmit) {
3640		if (isNew) {
3641			performSignIn();
3642		} else {
3643			document.forms[0].submit();
3644		}
3645	}
3646}
3647
3648function validateContact(idPrepend) {
3649	var alertMessage = "";
3650
3651	if ($(idPrepend + 'FirstName').val() == '' || $(idPrepend + 'FirstName').val() == 'First Name') {
3652		alertMessage += "Please enter a valid first name.\n";
3653	}
3654
3655	if ($(idPrepend + 'LastName').val() == '' || $(idPrepend + 'LastName').val() == 'Last Name') {
3656		alertMessage += "Please enter a valid last name.\n";
3657	}
3658
3659	if ($(idPrepend + 'Address1').val() == '' || $(+'Address1').val() == 'Address') {
3660		alertMessage += "Please enter a valid address.\n";
3661	}
3662
3663	if ($(idPrepend + 'City').val() == '' || $(idPrepend + 'City').val() == 'City') {
3664		alertMessage += "Please enter a valid city.\n";
3665	}
3666
3667	if ($(idPrepend + 'State').val() == '' || $(idPrepend + 'State').val() == 'ST') {
3668		alertMessage += "Please enter a valid " + getLowerCaseStateString() + ".\n";
3669	} else if (!RegExValidate('^[A-Z]{2}$', $(idPrepend + 'State').val(), 'i') || !RegExValidate('^[a-z]{2}$', $(idPrepend + 'State').val(), 'i')) {
3670		alertMessage += "Please enter a valid " + getLowerCaseStateString() + ".\n";
3671	}
3672
3673	if ($(idPrepend + 'PostalCode').val() == '' || (!isZipCode($(idPrepend + 'PostalCode').val(), intCountryCode))) {
3674		if (intCountryCode == 840)
3675			alertMessage += "Please enter a valid US zip code.\n";
3676		else if (intCountryCode == 124)
3677			alertMessage += "Please enter a valid Canadian postal code.\n";
3678		else
3679			alertMessage += "Please enter a valid zip code.\n";
3680
3681	}
3682
3683	if ($(idPrepend + 'Phone').val() == '' || !phoneValidate($(idPrepend + 'Phone').val())) {
3684		alertMessage += "Please enter a valid phone number.\n";
3685	}
3686
3687	return alertMessage;
3688}
3689
3690function validateRequiredProfile(alertMsgDetail) {
3691
3692	if (txtCompany != null) {
3693		if (txtCompany.value == '') {
3694			alertMsgDetail.doSubmit = false;
3695			alertMsgDetail.alertMsg += "Your company name cannot be blank.\n";
3696		}
3697	}
3698	if (txtAddress1.value == 'Address' || txtAddress1.value == '') {
3699		alertMsgDetail.doSubmit = false;
3700		alertMsgDetail.alertMsg += "Please enter Contact address.\n";
3701	}
3702	if (txtCity.value == 'City' || txtCity.value == '') {
3703		alertMsgDetail.doSubmit = false;
3704		alertMsgDetail.alertMsg += "Please enter City for contact address.\n";
3705	}
3706	if (txtState.value == 'ST' || txtState.value == '') {
3707		alertMsgDetail.doSubmit = false;
3708		alertMsgDetail.alertMsg += "Please enter State for contact address.\n";
3709	} else if (!RegExValidate('^[A-Z]{2}$', txtState.value, 'i') || !RegExValidate('^[a-z]{2}$', txtState.value, 'i')) {
3710		alertMsgDetail.doSubmit = false;
3711		alertMsgDetail.alertMsg += "Please enter a valid State for contact address.\n";
3712	}
3713	if (txtZip.value == 'Zip' || txtZip.value == '') {
3714		alertMsgDetail.doSubmit = false;
3715		alertMsgDetail.alertMsg += "Please enter Zip for contact address.\n";
3716	} else if (!RegExValidate('^[0-9]{5}$', txtZip.value, 'i')) {
3717		alertMsgDetail.doSubmit = false;
3718		alertMsgDetail.alertMsg += "Please enter a valid Zip for contact address.\n";
3719	}
3720
3721}
3722
3723//Get the contact list
3724function contactList(contactID) {
3725	$.ajax({
3726		url: '/MyAccount/ContactList?contactID=' + contactID,
3727		type: 'GET',
3728		success: function (data) {
3729			if (data.RedirectURL)
3730				window.location = data.RedirectURL;
3731			else {
3732				$('#addressesBlock').html(data);
3733				$('.section.selfClear').css('display', 'block');
3734				// some address blocks were not enhanced by Jquery.Mobile libraries so, solution
3735				// seems to be triggering pagecreate event
3736				$('#mainProfileCreate').trigger('pagecreate');
3737			}
3738		},
3739		error: function (jqXHR, textStatus, errorThrown) {
3740			alert('An error occurred');
3741		},
3742		beforeSend: function () {
3743			ajaxPostBackStart('Loading');
3744		},
3745		complete: function () {
3746			ajaxPostBackEnd();
3747		}
3748	});
3749}
3750
3751//Removes a contact
3752function contactDelete(contactID) {
3753	if (confirm('Are you sure you want to delete this address?')) {
3754		$.ajax({
3755			url: '/MyAccount/ContactDelete?contactID=' + contactID,
3756			type: 'GET',
3757			success: function (data) {
3758				$('#addressesBlock').html(data);
3759			},
3760			error: function (jqXHR, textStatus, errorThrown) {
3761				alert('The address could not be deleted.');
3762			},
3763			beforeSend: function () {
3764				ajaxPostBackStart('Loading');
3765			},
3766			complete: function () {
3767				ajaxPostBackEnd();
3768			}
3769		});
3770	}
3771}
3772
3773//Saves a contact
3774function contactSave(contactID, isMobileView, idPrepend, isEdit) {
3775
3776	isEdit = isEdit || false;
3777
3778	if (arguments.length == 1 && typeof isMobileView == 'undefined') {
3779		isMobileView = false;
3780	}
3781
3782	if (arguments.length >= 1 && arguments.length <= 2 && typeof idPrepend == 'undefined') {
3783
3784		idPrepend = "";
3785	}
3786
3787	idPrepend = "#" + idPrepend;
3788
3789	var result = validateContact(idPrepend);
3790
3791	var firstName = $(idPrepend + 'FirstName');
3792	var lastName = $(idPrepend + 'LastName');
3793	var address1 = $(idPrepend + 'Address1');
3794	var address2 = $(idPrepend + 'Address2');
3795	var city = $(idPrepend + 'City');
3796	var state = $(idPrepend + 'State');
3797	var postalcode = $(idPrepend + 'PostalCode');
3798	var phone = $(idPrepend + 'Phone');
3799
3800	var isDefault;
3801
3802	if (result == "") {
3803		isDefault = firstName.parents('.address').find('.isDefault').is(':checked');
3804		var token = $("#addressesBlock input[name='__RequestVerificationToken']").val();
3805		$.ajax({
3806			url: '/MyAccount/ContactSave',
3807			contentType: 'application/x-www-form-urlencoded',
3808			type: 'POST',
3809			dataType: 'json',
3810			data: {
3811				__RequestVerificationToken: token,
3812				ContactID: contactID,
3813				FirstName: firstName.val(),
3814				LastName: lastName.val(),
3815				Address1: address1.val(),
3816				Address2: address2.val(),
3817				City: city.val(),
3818				State: state.val(),
3819				PostalCode: postalcode.val(),
3820				Phone: phone.val(),
3821				IsDefault: isDefault
3822			},
3823			success: function (data) {
3824				if (data != null && data != undefined && data.RedirectURL) {
3825					window.location = data.RedirectURL;
3826				} else {
3827
3828					//var obj = jQuery.parseJSON(data);
3829					if (data.Successful == false) {
3830
3831						alert(data.ErrorMessage);
3832						return false;
3833
3834					} else {
3835
3836						contactList(0);
3837					}
3838
3839				}
3840			},
3841			error: function (jqXHR, textStatus, errorThrown) {
3842				alert('The address could not be saved.');
3843			},
3844			beforeSend: function () {
3845				ajaxPostBackStart('Loading');
3846			},
3847			complete: function () {
3848				ajaxPostBackEnd();
3849			}
3850		});
3851	} else {
3852		alert(result);
3853
3854		if (isMobileView) return false;
3855	}
3856
3857
3858	if (isMobileView && !isEdit) {
3859
3860		firstName.val("");
3861		lastName.val("");
3862		address1.val("");
3863		address2.val("");
3864		city.val("");
3865		//state = ...
3866		postalcode.val("");
3867		phone.val("");
3868
3869		return true;
3870	}
3871
3872}
3873
3874//Changes the default address on myaccount screen.
3875function changeDefaultContact(checkBox, contactID) {
3876	if (contactID == 0) {
3877		setDefaultContact(checkBox);
3878	} else {
3879		$.ajax({
3880			url: '/MyAccount/ContactSetDefault?contactID=' + contactID,
3881			type: 'GET',
3882			success: function (data) {
3883				setDefaultContact(checkBox);
3884			},
3885			error: function (jqXHR, textStatus, errorThrown) {
3886				alert('The default address could not be changed.');
3887			},
3888			beforeSend: function () {
3889				ajaxPostBackStart('Loading');
3890			},
3891			complete: function () {
3892				ajaxPostBackEnd();
3893			}
3894		});
3895	}
3896}
3897
3898//Changes the default address on myaccount screen.
3899function changeDefaultContactMobile(contactID) {
3900
3901	$.ajax({
3902		url: '/MyAccount/ContactSetDefault?contactID=' + contactID,
3903		type: 'GET',
3904		success: function (data) {
3905
3906		},
3907		error: function (jqXHR, textStatus, errorThrown) {
3908			alert('The default address could not be changed.');
3909		},
3910		beforeSend: function () {
3911			ajaxPostBackStart('Loading');
3912		},
3913		complete: function () {
3914			ajaxPostBackEnd();
3915		}
3916	});
3917
3918}
3919
3920function setDefaultContact(checkBox) {
3921	var $addressBlock;
3922	$('.address input[type=checkbox]').each(function () {
3923		this.checked = false;
3924		this.disabled = false;
3925	});
3926
3927	checkBox.checked = true;
3928	checkBox.disabled = true;
3929
3930	$('.address.active').removeClass('active');
3931	$addressBlock = $(checkBox).parents('.address');
3932	$addressBlock.addClass('active');
3933}
3934
3935function recover(username) {
3936	var responseFN = function (ajaxRequest) {
3937		alert(ajaxRequest);
3938	}
3939
3940	makeHttpRequestEx('/Services/ForgotPassword.ashx?Username=' +
3941        encodeURIComponent(username) + '&set=admin', null, responseFN, false);
3942}
3943
3944function SetPhotoMobile(photoType, createProfile) {
3945	SetPhoto(photoType, createProfile);
3946}
3947
3948
3949function SetPhoto(photoType, createProfile) {
3950	if (createProfile.toLowerCase() == 'true') {
3951		$.post('/MyAccount/CreateProfilePhoto?photoType=' + photoType, function (response) {
3952			$('.photo.fbPhoto').html(response);
3953			switch (photoType) {
3954				case 0:
3955					$('#SetRemovePhoto').val('False');
3956					break;
3957				case 1:
3958					$('#SetRemovePhoto').val('False');
3959					break;
3960				case 2:
3961					$('#SetRemovePhoto').val('True');
3962					break;
3963			}
3964		});
3965	} else {
3966		$.post('/MyAccount/ProfilePhoto?photoType=' + photoType, function (response) {
3967			if (response.RedirectURL)
3968				window.location.href = response.RedirectURL;
3969			else {
3970				$('.photo.fbPhoto').html(response);
3971				switch (photoType) {
3972					case 0:
3973						$('#SetRemovePhoto').val('False');
3974						break;
3975					case 1:
3976						$('#SetRemovePhoto').val('False');
3977						break;
3978					case 2:
3979						$('#SetRemovePhoto').val('True');
3980						break;
3981				}
3982			}
3983		});
3984	}
3985}
3986
3987function HasAcceptedTerms(url) {
3988
3989	var result = {
3990		status: 1,
3991		HasAcceptedTerms: true
3992	};
3993	if ($('#HasAcceptedTerms').is(':checked')) {
3994		return result;
3995	}
3996
3997	$.ajax({
3998		url: location.origin + url,
3999		type: 'POST',
4000		async: false,
4001		dataType: 'json',
4002		success: function (data) {
4003			result = data;
4004		},
4005		error: function (jqXHR, textStatus, errorThrown) {
4006			result = {
4007				status: 0,
4008				msg: 'Error encountered while checking terms acceptance.'
4009			};
4010		}
4011	});
4012
4013	return result;
4014}
4015
4016function openCpModalMobile(options) {
4017
4018	var msg;
4019	var title = options.title;
4020
4021	$.ajax({
4022		url: options.url,
4023		type: 'GET',
4024		async: false,
4025		cache: false,
4026		success: function (result) {
4027			msg = result;
4028		},
4029		error: function (xhr, textStatus, exception) {
4030			alert('Error encountered while loading modal.');
4031		}
4032	});
4033
4034	$('#popupBasic .header').html(title);
4035	$('#popupBasic .content').html(msg);
4036	$("#popupBasic").popup('open', {
4037		positionTo: 'window',
4038		overlayTheme: 'a'
4039	});
4040}
4041
4042function ShowTerms(onAccept) {
4043
4044	if ($('#IsMobile').val() == 'True') {
4045
4046		openCpModalMobile({
4047			title: 'Our Terms Have Changed',
4048			className: 'legalUpdate',
4049			isFrontEnd: true,
4050			url: '/MyAccount/Terms'
4051		});
4052
4053		$('.legalUpdate .button.accept').click(onAccept);
4054		$('.legalUpdate .button.cancel').click(DoNotAcceptMobile);
4055
4056	} else {
4057
4058		openCpModal({
4059			title: 'Our Privacy Policy/Terms and Conditions Have Changed',
4060			className: 'legalUpdate',
4061			isFrontEnd: true,
4062			url: '/MyAccount/Terms'
4063		});
4064
4065		$('.legalUpdate .button.accept').click(onAccept);
4066		$('.legalUpdate .modalClose').click(DoNotAccept);
4067	}
4068}
4069
4070
4071function DoNotAccept() {
4072	$('#login-fb-waiting-text').hide();
4073	$('#login-fb-waiting').hide();
4074	$('.loginBox').show();
4075	$('.fb-login').show();
4076	fb_busy = false;
4077	closeCpModal();
4078
4079	return false;
4080}
4081
4082function DoNotAcceptMobile() {
4083
4084	window.location = '/MyAccount';
4085
4086}
4087
4088// Returns TRUE if the password and confirm password field match.
4089function passwordFieldsMatch() {
4090	// NOTE: e_5 and e_6 are hard-coded IDs
4091	var passwordField = $('#e_5');
4092	var confirmPasswordField = $('#e_6');
4093	return passwordField.val() == confirmPasswordField.val();
4094};
4095function UpdateEmailCheck() {
4096	var self = this;
4097
4098	self.HandleEmailUpdate = function (emailElementID, originalEmail) {
4099		var updatedEmail = $('#' + emailElementID).val();
4100
4101		if (originalEmail == updatedEmail) {
4102			return true;
4103		}
4104
4105		else {
4106			return self.SendEmailUpdate(updatedEmail);
4107		}
4108	}
4109
4110	self.SendEmailUpdate = function (updatedEmail) {
4111		var url = '/MyAccount/UpdateEmail/Update';
4112		var success = false;
4113		$.ajax({
4114			url: url,
4115			async: false,
4116			type: 'post',
4117			data: { updatedEmailAddress: updatedEmail },
4118			success: function (response) {
4119				if (response.RedirectURL)
4120					window.location.href = response.RedirectUrl;
4121				else if (response.Success) {
4122					alert(response.Success);
4123					success = true;
4124				}
4125				else if (response.NoAction)
4126					success = true;
4127				else {
4128					alert(response.EmailTaken);
4129				}
4130			}
4131		});
4132		return success;
4133	}
4134};
4135

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.