document.write('
'); var SaaSFormStyles = "@media (max-width: 480px) { body [name^='scForm'] .body-div { width: 100% !important; } body [name^='scForm'] .body-div table { width: 100%; } body [name^='scForm'] .body-div table tbody { width: 100%; } body [name^='scForm'] .body-div table tbody tr { width: 100%; } body [name^='scForm'] .body-div table tbody tr td { width: 100%; } } body [name^='scForm'] .body-div table.hiddenElement { display: none; height: 0px; min-height: 0px; } body [name^='scForm'] .body-div table { box-sizing: content-box; line-height: normal; font-size: inherit; border: 0; padding: 0; margin: 0; } body [name^='scForm'] .body-div table tr { line-height: normal; border: 0; padding: 0; box-sizing: content-box; margin: 0; } body [name^='scForm'] .body-div table tr td { line-height: normal; box-sizing: content-box; border: 0; padding: 0; margin: 0; } body [name^='scForm'] .body-div table tr td .label { background: transparent; text-align: inherit; text-shadow: initial; white-space: normal; } body [name^='scForm'] .body-div table tr td input { height: auto; border-radius: 3px; font-size: 100%; line-height: normal; } body [name^='scForm'] .body-div table tr td div { line-height: normal; box-sizing: content-box; } body [name^='scForm'] .body-div table tr td .inputContainer { height: auto; } body [name^='scForm'] .body-div table tr td textarea { font-family: Arial, Helvetica, sans-serif; } body [name^='scForm'] .body-div table tr td .options.input label { display: inline-block; } body [name^='scForm'] .body-div .thankYouContainer { position: absolute; top: 0; left: 0; background: rgba(255,255,255,0.6); height: 100%; width: 100%; display: flex; justify-content: center; align-items: center; } body [name^='scForm'] .body-div .thankYouContainer .thankYouMessage { padding: 1em 1em 0 1em; margin: 0 1em 1em 1em; background: white; border: 1px solid rgba(0,0,0,0.3); border-radius: 0.28rem; position: relative; } body [name^='scForm'] .body-div .thankYouContainer .closeThankYou { position: absolute; top: 0; right: 0; background: 0; border: 0; font-weight: bold; font-size: 20px; font-family: Tahoma; line-height: 20px; padding: 0 5px 5px 5px; }";/*global jQuery, grecaptchaFormSiteKey */ if (typeof jQueryScriptOutputted == 'undefined') var jQueryScriptOutputted = false; var errorStyles = '.errorTip { display: inline-block; position:absolute; } .errorTip .errorInner{ position: relative; background: #d54333; border: 2px solid #661e1e; padding:5px;border-radius:7px;color:white;font-size:14px; cursor:pointer; max-width:350px; box-shadow: 3px 3px 10px rgba(0,0,0,0.3); }.errorInner:after, .errorInner:before { right: 100%; border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none;}.errorInner:after { border-color: rgba(213, 67, 51, 0); border-right-color: #d54333; border-width: 10px; top: 50%; margin-top: -10px;}.errorInner:before { border-color: rgba(102, 30, 30, 0); border-right-color: #661e1e; border-width: 13px; top: 50%; margin-top: -13px;}'; if (typeof scFormLoadStart == 'undefined') var scFormLoadStart = false; if (typeof scFormLoaded == 'undefined') var scFormLoaded = false; if (typeof scPortableLoaded == 'undefined') var scPortableLoaded = false; if (typeof scTimeoutLoaded == 'undefined') var scTimeoutLoaded = false; if (typeof scButtonLoaded == 'undefined') var scButtonLoaded = false; if (typeof scScriptsLoading == 'undefined') var scScriptsLoading = false; if (typeof scScriptsLoaded == 'undefined') var scScriptsLoaded = false; if (typeof SaaSFormStyles === 'undefined') var SaaSFormStyles = ''; if (window.formGrecaptchaElements === undefined) { window.formGrecaptchaElements = {}; } // Gets jQuery function scInitJQuery() { //if the jQuery object isn't available if (typeof(jQuery) == 'undefined') { if (! jQueryScriptOutputted) { //only output the script once.. jQueryScriptOutputted = true; var script = document.createElement("SCRIPT"); script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'; script.type = 'text/javascript'; document.getElementsByTagName("head")[0].appendChild(script); scLoadScripts(); } setTimeout("scInitJQuery()", 50); } else if (!scScriptsLoading){ scLoadScripts(); } } // Adds error styles and validation script function scLoadScripts() { scScriptsLoading = true; if (scScriptsLoaded) return true; if (typeof jQuery != 'undefined') { var script = document.createElement("SCRIPT"); script.src = scAppUrl+'channels/form/js/formValidation.js'; script.type = 'text/javascript'; document.getElementsByTagName("head")[0].appendChild(script); var gApi = document.createElement("SCRIPT"); gApi.src = "https://www.google.com/recaptcha/api.js?onload=formGrecaptchaLoadCallback&render=explicit"; gApi.type = "text/javascript"; document.getElementsByTagName("head")[0].appendChild(gApi); var script2 = document.createElement("SCRIPT"); script2.src = scAppUrl + 'thirdparty/jquery-datetimepicker/jquery.datetimepicker.js'; script2.type = 'text/javascript'; document.getElementsByTagName('head')[0].appendChild(script2); var style = document.createElement('LINK'); style.href = scAppUrl + 'thirdparty/jquery-datetimepicker/jquery.datetimepicker.css'; style.type = 'text/css'; style.rel = 'stylesheet'; document.getElementsByTagName('head')[0].appendChild(style); jQuery( "" ).appendTo( "head" ); scScriptsLoaded = true; saasBindKeys(); } else{ setTimeout(function() { scLoadScripts(); }, 50); } } /** * Bind the escape key to hide modal forms * * @return void */ function saasBindKeys() { jQuery(document).keyup(function(e) { if (e.keyCode == 27) { saasRemoveModal(); } // esc }); } /** * Called by the (thirdparty) Grecaptcha JS after it has loaded * Initalizes any captchas that have not yet been rendered * * @return void */ function formGrecaptchaLoadCallback () { var i; var elements = window.formGrecaptchaElements; for (i in elements) { if (elements.hasOwnProperty(i)) { if (!elements[i].rendered) { elements[i].form.renderGrecaptchaElement(); } } } } /** * Load a form using the config passed from the server * * @param object config Form config: * { * id: random unique id * formId: form's id * type: "portable" or "modal" * target: the form's desired target attribute * targetElement: id of element that the form will be inserted into * formHtml: the actual html of the form * thankYouHtml: the html of the thank you message * modal: modal config (timeout length, button, etc) * } */ function SaaSForm (config) { /** * Internal Data */ var form = { id: config.id, formId: config.formId, type: config.type, targetElement: config.targetElement, container: undefined, element: undefined, context: this, formHtml: config.formHtml, thankYouHtml: config.thankYouHtml.replace(/\\"/g, '"'), defaultValues: {}, }; /** * Expose methods */ this.renderGrecaptchaElement = renderGrecaptchaElement; this.getElement = getElement; init(); /** * Initialize the form if jQuery has been loaded. This method will place the form's HTML into the container * element and bind the relevant events. */ function init () { if (window.jQuery !== undefined) { switch(form.type) { case 'portable': initPortable(); break; case 'modal': initModal(); break; } /** * Trigger the load event. Users can listen to the event to run additional logic once the form has loaded */ jQuery(document).trigger("portableFormDisplayed", [form.element, form.formId, form.context]); } else { /** * Wait for jQuery to load */ setTimeout(function () { init(); }, 50); } } /** * Initialize a portable form. Create the form's container withhin the target element and set up the form * * @return void */ function initPortable () { var container = form.container = jQuery('#' + config.targetElement); container.html('
'); var element = form.element = form.container.find('#scPortableForm-' + form.formId); element.append(form.formHtml); element.find('style').remove(); element.find('form').attr('id', 'scInlineForm-' + form.formId); element.find('.scVerifyEmail').hide(); if (element.find('.footer-div').length > 0) { element.find('.footer-div').appendTo(element.find('.body-div')); jQuery('.body-div').css('height','auto'); } element.find('form').submit(function(e) { onSubmit(e); }); if (isMobile()) { element.find('.body-div').css('width', '100%'); element.find('td').css('width', '100%'); } storeDefaultValues(); setupDatePickers(); setupCaptchas(); setupDefaultValues(); } /** * Initialize a modal form. Create the form's container on the body and set up the form * * @return void */ function initModal () { jQuery('body').append(''); if (jQuery('.scFormContainerModal .footer-div').length > 0) { jQuery('.scFormContainerModal .footer-div').appendTo('.scFormContainerModal .body-div'); jQuery('.body-div').css('height','auto'); } var container = form.element = jQuery('#scFormContainerModal-' + form.id); container.find('form').css('margin-top', '6%'); container.find('.body-div').css('box-shadow', '0px 1px 4px #333'); container.find('style').remove(); container.find('div:first').css('background', 'transparent'); container.find('.body-div').css('position', 'relative'); container.find('.body-div').css('margin', '0 auto'); container.find('.body-div').append("
X
"); container.find('.scVerifyEmail').hide(); jQuery('.scModalFormCloseButton').click(function() { saasRemoveModal(); }); container.find('form').submit(function(e) { onSubmit(e); }); storeDefaultValues(); setupDatePickers(); setupCaptchas(); setupDefaultValues(); if (typeof config.modal.timeoutDisplay != 'undefined' && config.modal.timeoutDisplay) { shouldShowForm(); } if (typeof config.modal.displayButton != 'undefined' && config.modal.displayButton) { loadButton(); } } /** * Scan the fields and store any default values so they can be used later for validation. * We only care about required fields * * @return void */ function storeDefaultValues() { form.element.find('.required').each(function () { form.defaultValues[jQuery(this).attr('name')] = jQuery(this).val().trim(); }); } /** * Validate the form before submission * * @return bool */ function validate() { var hasError = false; var element = form.element; element.find('td').each(function () { var field = jQuery(this); var type = field.attr('id').split('_')[0]; switch (type) { case "MatrixElement": hasError = validateMatrix(field) || hasError; break; case "AddressElement": hasError = validateAddress(field) || hasError; break; case "CheckboxElement": hasError = validateCheckbox(field) || hasError; break; case "RadioElement": hasError = validateCheckbox(field) || hasError; break; case "VoiceElement": hasError = validateNumber(field) || hasError; break; case "SMSElement": hasError = validateNumber(field) || hasError; break; case "FaxElement": hasError = validateNumber(field) || hasError; break; case "EmailElement": hasError = validateEmail(field) || hasError; break; default: hasError = validateField(field) || hasError; break; } }); return !hasError; } /** * Check if a given field is required * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function fieldIsRequired(field) { return field.find('.required:not(.prefix)').length > 0; } /** * Render the error message that exists in a given field. * * @param jQueryObject field The field (top level table element) jQuery object * * @return void */ function renderError(field) { field.find('.errorMessage').css('display', 'block'); } /** * Validate a text field * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateField(field) { var hasError = false; if (fieldIsRequired(field)) { field.find('.required:not(.prefix)').each(function () { if (jQuery(this).is(":visible") && jQuery(this).val().trim() === '') { hasError = true; } }); } field.find('[data-minlimit]').each(function () { var value = jQuery(this).val().trim(); if (value !== "" && value.length < jQuery(this).data('minlimit')) { hasError = true; } }); if (hasError) { renderError(field); } return hasError; } /** * Validate a phone number field * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateNumber(field) { var hasError = false; var value = field.find('.prefix').val().trim() + field.find('.numberInput').val().trim(); if ((fieldIsRequired(field) && value === "") || (value.length > 0 && (value.length < 5 || value.search(/[a-zA-Z]+/) != -1))) { hasError = true; renderError(field); } return hasError; } /** * Validate an email field * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateEmail(field) { var hasError = false; var input, value; var emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; input = field.find('input[type="text"]'); value = input.val().trim(); if (fieldIsRequired(field)) { if (value === "" || value === form.defaultValues[input.attr('name')]) { hasError = true; } } if (emailRegex.test(value) === false) { hasError = true; } if (hasError) { renderError(field); } return hasError; } /** * Validate an address. If its required, ensure that at least: address1, country, city and zip are completed. * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateAddress(field) { var hasError = false; var inputs = [ 'address1[value]', 'country[value]', 'city[value]', 'zip[value]', ]; var i; if (fieldIsRequired(field)) { for (i = 0; i < inputs.length; i++) { if (field.find('[name="' + inputs[i] + '"]').val().trim() === "") { hasError = true; } } } if (hasError) { renderError(field); } return hasError; } /** * Validate a checkbox. If its required ensure that at least one has been checked * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateCheckbox(field) { var hasError = false; if (fieldIsRequired(field)) { if (field.find("input:checked").length === 0) { hasError = true; renderError(field); } else { field.find("input:checked").parent().each(function () { if (jQuery(this).find("input[type=text]").length !== 0) { if (jQuery(this).find("input[type=text]").val().trim() === '') { hasError = true; renderError(field); } } }); } } return hasError; } /** * Validate a radio matrix. Ensure that for each question at least one radio has been checked * * @param jQueryObject field The field (top level table element) jQuery object * * @return bool */ function validateMatrix(field) { var hasError = false; var choices = []; var choice; var i; if (fieldIsRequired(field)) { field.find('input[type="radio"]').each(function () { var name = jQuery(this).attr('name'); if (choices.indexOf(name) === -1) { choices.push(name); } }); if (choices.length > 0) { for (i = 0; i < choices.length; i++) { choice = choices[i]; if (!jQuery('input[name="' + choice + '"]').is(":checked") || jQuery('input[name="' + choice + '"]:checked').val() == 'null') { hasError = true; renderError(field); } } } } return hasError; } /** * Get the form's jQuery element * * @return jQueryObject */ function getElement() { return form.element; } /** * Internal method for configuring a captcha to be rendered. If the captcha library has not yet loaded: * store the data elsewhere for the formGrecaptchaLoadCallback to use. * * @return void */ function _renderGrecaptchaElement () { window.formGrecaptchaElements[form.id] = { form: form.context, rendered: false, }; if (window.grecaptcha !== undefined) { renderGrecaptchaElement(); } } /** * Render the captcha using the Google Recaptcha library. This method is also exposed * for the formGrecaptchaLoadCallback to use. * * @return void */ function renderGrecaptchaElement() { var captcha = window.formGrecaptchaElements[form.id]; if (captcha.rendered === false) { var captchaElement = form.element.find('.recaptcha'); captcha.widgetId = window.grecaptcha.render(captchaElement[0], { sitekey: grecaptchaFormSiteKey, callback: function () { form.element.find('input[type="submit"]').attr('disabled', false); }, "expired-callback": function () { form.element.find('input[type="submit"]').attr('disabled', true); } }); captcha.rendered = true; form.element.find('input[type="submit"]').attr('disabled', true); } } /** * Submission event for the form. Validates the fields and then "posts" the data. * * @param DOMEvent e The submission event from the form * * @return void */ function onSubmit (e) { cleanErrors(); if (validate()) { //Disable Submit Element so only one copy of the form can be submitted form.element.find('input[type="submit"]').each(function(){ jQuery(this).attr('disabled', true); }); if (config.target == "_self") { e.preventDefault(); var data = form.element.find('form').serializeArray(); var html = ""; html += '
'; html += '
'; html += mergeValues(form.thankYouHtml, data); html += ''; html += "
"; html += "
"; jQuery('body').append(''); jQuery(document).trigger("portableFormSubmitted", [form.element, form.formId, form.context]); setTimeout(function() { var iframe = jQuery("#saasPortableIframeForm-" + form.id); iframe.contents().find("body").append(form.element.find('form').clone()); iframe.contents().find('form').unbind('submit'); form.element.find('select').each(function () { var name = jQuery(this).attr('name'); iframe.contents().find('[name="' + name + '"]').val(jQuery(this).val()); }); iframe.contents().find('form').submit(); form.element.find('.body-div').css('position', 'relative').append(html); form.element.find('.closeThankYou').click(function () { form.element.find('.thankYouContainer').remove(); }); form.element.find('input[type="submit"]').attr('disabled', false); }, 100); } } else { e.preventDefault(); } } /** * Return all errors to their default hidden state * * @return void */ function cleanErrors() { form.element.find('.errorMessage').css('display', 'none'); } /** * Load the button used for modal forms. Bind the show callback to its click event * * @return void */ function loadButton() { // Build the button jQuery('body').append('
'); var container = jQuery('#scButtonContainer-' + form.id); var modal = config.modal; var button = jQuery("