var EntityFormUX = { // Option Set - Dropdown Format // Hide an Option from dropdown RemoveOptionsFromOptionSetDropdown: function(attributeName, optionValue) { // jQuery show/hide doesn't work. Hence Bootstrap Hidden Class is used $("#" + attributeName + " option[value='" + optionValue + "']").addClass("hidden"); }, // Show the previously hidden option using RemoveOptionsFromOptionSetDropdown ShowOptionsFromOptionSetDropdown: function(attributeName, optionValue) { $("#" + attributeName + " option[value='" + optionValue + "']").removeClass("hidden"); }, // Assuming the options are in a range, so you don't need to code them one by one ShowHideOptionsFromDropdownRange: function(attributeName, minOptionValue, maxOptionValue, show) { for (var i = minOptionValue; i <= maxOptionValue; i++) { if (show) { EntityFormUX.ShowOptionsFromOptionSetDropdown(attributeName, i); } else { EntityFormUX.RemoveOptionsFromOptionSetDropdown(attributeName, i); } } }, // Option Set - Radio Button Format // Hide an Option Radio Button RemoveOptionsFromOptionSetRadioButtons: function(attributeName, optionValue) { var option = $("input[name$='" + attributeName + "'][value='" + optionValue + "']"); if (option.length > 0) { var radioButtonId = option.attr('id'); option.hide(); $("label[for='" + radioButtonId + "']").hide(); } }, // Show the previous hidden option using RemoveOptionsFromOptionSetRadioButtons ShowOptionsFromOptionSetRadioButtons: function(attributeName, optionValue) { var option = $("input[name$='" + attributeName + "'][value='" + optionValue + "']"); if (option.length > 0) { var radioButtonId = option.attr('id'); option.show(); $("label[for='" + radioButtonId + "']").show(); } }, // Option Set General ReplaceOptionSetLabelValue: function(attributeName, optionValue, overrideLabel) { $("#" + attributeName + " option[value='" + optionValue + "']").text(overrideLabel); }, SetOptionSetDropdownReadonly: function(attributeName) { $("#" + attributeName).attr('readonly', 'readonly').attr('disabled', 'disabled').addClass('readonly'); }, // This only works if the Option Set Field is set to read-only using SetOptionSetDropdownReadonly // If the field is read-only at CRM Form, Entity Form will not save any changes on the value RemoveOptionSetDropdownReadonly: function(attributeName) { $("#" + attributeName).removeAttr('readonly').removeAttr('disabled').removeClass('readonly'); }, // Radio Buttons - Works for Both Two Options and Option Set // Set Radio Button Selection SetRadioButtonSelectionValue: function(attributeName, settingValue) { $('input[name$="' + attributeName + '"][value="' + settingValue + '"]').prop('checked', true); $("#" + attributeName).trigger("change"); }, // Reset Radio Buttons Selections - Clear Selection ResetRadioButtonSelection: function(attributeName) { $("input[name$='" + attributeName + "']:checked").removeAttr("checked").trigger("change"); }, // Get Radio Buttons selected value GetRadioButtonSelectionValue: function(attributeName) { return $("input[name$='" + attributeName + "']:checked").val(); }, // Two-Options - Checkbox // Set Checkbox Values // Expecting true/false boolean for settingValue SetCheckboxFieldValue: function(attributeName, settingValue) { var $field = $("#" + attributeName); if ($field.length == 0) { return; } if (settingValue) { $field.attr("checked", "checked"); } else { $field.removeAttr("checked"); } $field.trigger("change"); }, // Lookup SetLookupReadOnly: function (attributeName) { var attributeTextBox = $("#" + attributeName + "_name"); if (attributeTextBox.length > -1) { attributeTextBox.addClass("aspNetDisabled").attr("disabled", "disabled"); var lookupBtnGroup = attributeTextBox.parent().find(".input-group-btn"); if (lookupBtnGroup.length > -1) { lookupBtnGroup.addClass("hidden"); } } }, // Clear a lookup field value ClearLookupFieldValue: function(attributeName) { EntityFormUX.SetLookupFieldValue(attributeName, '', '', ''); }, // Set a lookup field value SetLookupFieldValue: function(attributeName, entityLogicalName, settingValue, settingName) { var $field = $("#" + attributeName); if ($field.length == 0) { return; } var $nameField = $("#" + attributeName + "_name"); if ($nameField.length == 0) { return; } var $lookupTargetField = $("#" + attributeName + "_entityname"); if ($lookupTargetField.length == 0) { return; } $nameField.val(settingName); $lookupTargetField.val(entityLogicalName); $field.val(settingValue).trigger("change"); }, // Date SetDateFieldReadOnly: function(attributeName) { var datetimePickerTextbox = $("input[aria-labelledby='" + attributeName + "_label']"); datetimePickerTextbox.attr('readonly', 'readonly'); datetimePickerTextbox.addClass('readonly'); var pickerIconSpan = datetimePickerTextbox.parent().find(".input-group-addon"); if (pickerIconSpan.length > 0) { pickerIconSpan.attr('style', 'display:none;'); } }, // This only works if the Date Field is set to read-only using SetDateFieldReadOnly // If the field is read-only at CRM Form, Entity Form will not save any changes on the value RemoveDateFieldReadOnly: function(attributeName) { var datetimePickerTextbox = $("input[aria-labelledby='" + attributeName + "_label']"); datetimePickerTextbox.removeAttr('readonly', 'readonly'); datetimePickerTextbox.removeClass('readonly'); var pickerIconSpan = datetimePickerTextbox.parent().find(".input-group-addon"); if (pickerIconSpan.length > 0) { pickerIconSpan.removeAttr('style', 'display:none;'); } }, // This only works on early 7.x version SetDateAttributeValue: function(attributeName, dateStringValue) { // It's the same as Text Box Value. Just need to get the date time format correct // Beware of passing values. If Attribute only accepts date only, please ensure the value does not contain time. // Looking for Format like 2017-04-26T00:00:00.0000000 $("#" + attributeName).val(dateStringValue); $("#" + attributeName).trigger("change"); }, // DatePicker Method of 7.0.18 / 8.x // Please refer to http://eonasdan.github.io/bootstrap-datetimepicker/version3/ for references (7.0.18 and later) // 2017-08-21 - updated documentation here: http://eonasdan.github.io/bootstrap-datetimepicker/#bootstrap-3-datepicker-v4-docs // Use NULL to clear value SetDatePickerValue: function(attributeName, dateValue) { var targetDatetimepickerTextbox = $("input[aria-labelledby='" + attributeName + "_label']"); var targetDatetimepickerParentDiv = targetDatetimepickerTextbox.parent(); targetDatetimepickerParentDiv.data("DateTimePicker").date(dateValue); $("#" + attributeName).trigger("change"); }, // Extension - Copy Date on Change CopyDateOnChange: function(sourceAttributeName, targetAttributeName) { var sourceDatetimepickerTextbox = $("input[aria-labelledby='" + sourceAttributeName + "_label']"); var sourceDatetimepickerParentDiv = sourceDatetimepickerTextbox.parent(); var targetDatetimepickerTextbox = $("input[aria-labelledby='" + targetAttributeName + "_label']"); var targetDatetimepickerParentDiv = targetDatetimepickerTextbox.parent(); sourceDatetimepickerParentDiv.on('dp.change', function (e) { EntityFormUX.SetDatePickerValue(targetAttributeName, e.date); }); }, ValidateDate1MustBeLaterThanDate2: function(date1AttributeName, date2AttributeName) { var date1DatetimepickerTextbox = $("input[aria-labelledby='" + date1AttributeName + "_label']"); var date1DatetimepickerParentDiv = date1DatetimepickerTextbox.parent(); var date2DatetimepickerTextbox = $("input[aria-labelledby='" + date2AttributeName + "_label']"); var date2DatetimepickerParentDiv = date2DatetimepickerTextbox.parent(); if (EntityFormUX.ValidateDateTimeHasValue(date1AttributeName) && EntityFormUX.ValidateDateTimeHasValue(date2AttributeName)) { // getDate throws an error. Parse the date instead. var date1 = date1DatetimepickerParentDiv.data("DateTimePicker").date(); var date2 = date2DatetimepickerParentDiv.data("DateTimePicker").date(); return (date2 < date1); } // Either one of the field has no value. Leave it to other validators return true; }, ValidateDateIsOrLaterThanToday: function(attributeName) { var sourceDatetimepickerTextbox = $("input[aria-labelledby='" + attributeName + "_label']"); var sourceDatetimepickerParentDiv = sourceDatetimepickerTextbox.parent(); if (EntityFormUX.ValidateDateTimeHasValue(attributeName)) { var today = new Date().setHours(0, 0, 0); // midnight var sourceDate = sourceDatetimepickerParentDiv.data("DateTimePicker").date(); return (today < sourceDate); } // The field does not have any value. Leave it to other validators return true; }, // CRM Min Date Allowed is Jan 1, 1900 // Example // var minDate = moment("01/01/1990", "MM/DD/YYYY"); // EntityFormUX.SetDatePickerMinDateAllowed("adoxio_birthdate", minDate); SetDatePickerMinDateAllowed: function(attributeName, minDate) { $("#" + attributeName).next().data("DateTimePicker").minDate(minDate); }, // Some Business Requirement Requires limited date, say 18 years or older // var eighteenYearsAgo = moment().subtract(18, 'years'); // var maxDate = eighteenYearsAgo; // EntityFormUX.SetDatePickerMaxDateAllowed("adoxio_birthdate", maxDate); SetDatePickerMaxDateAllowed: function(attributeName, maxDate) { $("#" + attributeName).next().data("DateTimePicker").maxDate(maxDate); }, /* // This is just a sample. And it only does format check. If you need additional logic, please add accordingly // The error message is only in English. Consider using Snippets which will provide message in corresponding language. // Call this method on form init for date picker validation SampleAddValidateDatePickerFormatOnChange: function(attributeName) { // Call this otherwise, the first load might render Chinese instead of default language. // It can be in the moment.locale("en"); var datetimePickerTextbox = $("input[aria-labelledby='" + attributeName + "_label']"); var attributeTextbox = $("#" + attributeName); var dateFormatConverter = window.dateFormatConverter; var dateOnly = attributeTextbox.data('type') === 'date'; var dateFormat = dateFormatConverter.convert(attributeTextbox.closest('[data-dateformat]').data('dateformat') || 'M/d/yyyy', dateFormatConverter.dotNet, dateFormatConverter.momentJs); var timeFormat = dateFormatConverter.convert(attributeTextbox.closest('[data-timeformat]').data('timeformat') || 'h:mm tt', dateFormatConverter.dotNet, dateFormatConverter.momentJs); var dateTimeFormat = dateOnly ? dateFormat : (dateFormatConverter.convert(attributeTextbox.closest('[data-datetimeformat]').data('datetimeformat'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat)); var keyMap = { 'tab': 9, 9: 'tab', 'escape': 27, 27: 'escape', 'enter': 13, 13: 'enter' }; function ValidateEnteredDateFormat() { $("#" + attributeName + "_formatnotice").remove(); var val = datetimePickerTextbox.val().trim(); var textbox = $("#" + attributeName); if (val) { var d = moment(val, dateTimeFormat, true); if (!d.isValid()) { textbox.before("Date Entered was: " + val + ". Please enter date in format of " + dateTimeFormat + ""); } } } datetimePickerTextbox.bindFirst("change", ValidateEnteredDateFormat); datetimePickerTextbox.bindFirst("keydown", function (e) { if (e.keyCode == keyMap.enter) { ValidateEnteredDateFormat(); } }); }, */ // Text // Set textbox values // Applicable to Textbox, TextAreas, DateTime (Early 7.x), Option Set as Select(Dropdown) SetTextboxFieldValue: function(attributeName, settingValue) { var $field = $("#" + attributeName); if ($field.length == 0) { return; } $field.val(settingValue).trigger("change"); }, SetTextboxReadOnly: function(attributeName) { $("#" + attributeName).attr('readonly', 'readonly'); $("#" + attributeName).addClass('readonly'); }, // This only works if the field is set as Readonly using SetTextboxReadOnly // If the field is read-only at CRM Form, Entity Form will not save any changes on the value RemoveTextboxReadOnly: function(attributeName) { $("#" + attributeName).removeAttr('readonly'); $("#" + attributeName).removeClass('readonly'); }, // Attributes - General // This is using HTML Tooltip. // OOB Tooltip at Entity Form will display the description field of the attribute // Use this if you want to override AddToolTip: function(attributeName, toolTipValue) { $("#" + attributeName + "_label").attr("title", toolTipValue); }, // This will enable the Bootstrap Tooltip and will only show the label of the field EnableBootstrapToolTip: function(attributeName) { $("#" + attributeName + "_label").attr("data-toggle", "tooltip"); }, // Hide the entire tab where the attribute control is located HideControlTab: function(attributeName) { EntityFormUX.AddStyleToClosestTabColumn(attributeName, "hidden"); }, // Entity Form Metadata adding a CSS hidden to the control only hides the control but not the label // This will hide the control with the label HideControlWithLabel: function(attributeName) { EntityFormUX.AddStyleToClosestTd(attributeName, "hidden"); }, // Show the control with its label // This only works if the control is hidden using HideControlWithLabel // This will NOT work if the Control is not in the CRM Form Layout, or its label is set to not visible at CRM ShowControlWithLabel: function(attributeName) { EntityFormUX.RemoveStyleToClosestTd(attributeName, "hidden"); }, HighlightControl: function(attributeName, highlightAlertClass) { EntityFormUX.AddStyleToClosestTd(attributeName, "alert"); EntityFormUX.AddStyleToClosestTd(attributeName, highlightAlertClass); }, RemoveHighlightOnControl: function(attributeName, highlightAlertClass) { EntityFormUX.RemoveStyleToClosestTd(attributeName, "alert"); EntityFormUX.RemoveStyleToClosestTd(attributeName, highlightAlertClass); }, SetAttributeLabel: function(attributeName, labelValue) { var labelControl = $("#" + attributeName + "_label"); if (labelControl.length > 0) { labelControl.html(labelValue); } }, // Tab // Hide the entire tab // For this to work, one must add a Entity Form metadata for the tab // At the Label, Change it to whatever it is called and then append the following // // For example: // By having this, it allows the JavaScript to find the h2 tag and toggle appearance HideTab: function(tabName) { var tabDiv = $('div[data-name$="' + tabName + '"]'); if (!tabDiv.hasClass("hidden")) { tabDiv.addClass("hidden"); var tabLabelDiv = $(".tab-" + tabName); var tabLabelH2 = tabLabelDiv.parent(); tabLabelH2.addClass("hidden"); } }, // Section // Hide Section By Name HideSectionByName: function(sectionName) { EntityFormUX.AddClassToSection(sectionName, "hidden"); }, // Show Section By Name // This only works if the section was hidden programmatically using HideSectionByName // Hidden Section at CRM Form Configuration will not be shown on Entity Forms ShowSectionByName: function(sectionName) { EntityFormUX.RemoveClassFromSection(sectionName, "hidden"); }, // Subgrid // When toggling on the Search functionality at the subgrid // CRM force the subgrid label to become visible // And it's sometimes redundant to the already visible Section Label HideSubgridLabel: function(subgridSchemaName) { $('label[for="' + subgridSchemaName + '"]').hide(); }, // Starting from 7.0.21ish, Entity List added a table-fluid class on load by JavaScript // This class is added after the on-load event and does not have any event trigger // The CSS behavior is to make the table become rows instead of rendering columns when the width of the device is too narrow // To maintain the table render as a table with columns, use this method to remove that table-fluid class RemoveEntityListTableFluidClass: function() { $(".entity-grid").ready(function () { setTimeout(RemoveTableFluidClassFromSubgrid, 1000, ""); }); }, RemoveSubgridTableFluidClass: function (subgridName) { $("#" + subgridName).ready(function () { setTimeout(RemoveTableFluidClassFromSubgrid, 1000, subgridName); }); }, RemoveTableFluidClassFromSubgrid: function(subgridName) { var entitygridComponent = $(".entity-grid"); if (subgridName != "") { var mySubgrid = $("#" + subgridName); entitygridComponent = mySubgrid.find(".entity-grid"); } var tableFluidComponent = entitygridComponent.find(".table-fluid"); if (tableFluidComponent.length) { tableFluidComponent.removeClass("table-fluid"); } else { setTimeout(EntityFormUX.RemoveTableFluidClassFromSubgrid, 500, subgridName); } }, RemoveIFrameTableFluidClass: function(iFrameName) { $("iframe#" + iFrameName).ready(function () { setTimeout(EntityFormUX.RemoveTableFluidClassFromIFrame, 3000, iFrameName); }); }, RemoveTableFluidClassFromIFrame: function(iFrameName) { var myIFrame = $("iframe#" + iFrameName); var myIFrameContents = myIFrame.contents(); var entitygridComponent = myIFrameContents.find(".entity-grid"); var tableFluidComponent = entitygridComponent.find(".table-fluid"); if (tableFluidComponent.length) { tableFluidComponent.removeClass("table-fluid"); } else { setTimeout(EntityFormUX.RemoveTableFluidClassFromIFrame, 500, iFrameName); } }, // Validations // Required At Least 1 Validator at the Form already. Otherwise, the Page_Validators will not be available // Add red asterisk to the Control AddRedAsteriskToRequiredControl: function(attributeName) { var controlLabel = $("#" + attributeName + "_label"); if (controlLabel.length > 0) { var controlLabelParent = $("#" + attributeName + "_label").parent(); if (!controlLabelParent.hasClass("required")) { controlLabelParent.addClass("required"); } } }, RemoveRedAsteriskFromRequiredControl: function(attributeName) { var controlLabel = $("#" + attributeName + "_label"); if (controlLabel.length > 0) { var controlLabelParent = $("#" + attributeName + "_label").parent(); if (controlLabelParent.hasClass("required")) { controlLabelParent.removeClass("required"); } } }, // Ignore Hidden Fields IsControlHidden: function(attributeName) { var control = $("#" + attributeName); if (control.length > 0) { if (control.closest("td").hasClass("hidden")) { return true; } return false; } return true; }, ToggleValidator: function(attributeName, enable) { var validatorId = "CustomRequiredFieldValidator" + attributeName; if (enable) { EntityFormUX.AddRedAsteriskToRequiredControl(attributeName); } else { EntityFormUX.RemoveRedAsteriskFromRequiredControl(attributeName); } for (i = 0; i < Page_Validators.length; i++) { if (Page_Validators[i].id == validatorId) { // toggle Validator ValidatorEnable(Page_Validators[i], enable); return true; } } return false; }, // To Remove a required validation, execute // EntityFormUX.RemovePageRequiredFieldValidatorsFor("firstname"); RemovePageRequiredFieldValidatorsFor: function(attributeName) { EntityFormUX.ToggleValidator(attributeName, false); }, AddPageRequiredFieldValidatorsFor: function(attributeName, attributeControlType, invalidateMessage, validationGroup) { if (typeof (Page_Validators) == 'undefined') return; if (validationGroup == null) { validationGroup = ""; } if (EntityFormUX.ToggleValidator(attributeName, true)) { return; } if (invalidateMessage == null || invalidateMessage == "") { var attributeLabel = $("#" + attributeName + "_label"); if (attributeLabel.length > 0) { invalidateMessage = attributeLabel.text() + " is a required field."; } } var aValidator = document.createElement('span'); aValidator.style.display = "none"; aValidator.id = "CustomRequiredFieldValidator" + attributeName; aValidator.controltovalidate = attributeName; aValidator.errormessage = "" + invalidateMessage + ""; aValidator.validationGroup = validationGroup; aValidator.initialvalue = ""; aValidator.evaluationfunction = function () { switch (attributeControlType) { case "datetime": return EntityFormUX.ValidateDateTimeHasValue(attributeName); break; case "checkbox": return EntityFormUX.ValidateCheckboxHasChecked(attributeName); break; case "radio": return EntityFormUX.ValidateOptionSetRadioHasSelectedValue(attributeName); break; case "optionsetasradio": return EntityFormUX.ValidateOptionSetRadioHasSelectedValue(attributeName); break; case "optionsetasdropdown": return EntityFormUX.ValidateOptionSetDropdownHasSelectedValue(attributeName); break; case "lookup": return EntityFormUX.ValidateLookupControlHasValue(attributeName); break; default: return EntityFormUX.ValidateTextboxHasValue(attributeName); break; } }; // Add the new validator to the page validators array Page_Validators.push(aValidator); }, // Expecting attributeSchemaNameDelimitedString in ",,", etc AddRequiredAtLeastOneCheckedboxValidator: function(attributeSchemaNameDelimitedString, validatorName, invalidateMessage, validationGroup) { if (typeof (Page_Validators) == 'undefined') return; if (validationGroup == null) { validationGroup = ""; } var validatorId = "CustomValidator" + validatorName; var isValidatorExist = false; for (i = 0; i < Page_Validators.length; i++) { if (Page_Validators[i].id == validatorId) { ValidatorEnable(Page_Validators[i], true); isValidatorExist = true; break; } } // Don't need to add validator again if (isValidatorExist) return; var attributeNameArray = attributeSchemaNameDelimitedString.split(","); var aValidator = document.createElement('span'); aValidator.style.display = "none"; aValidator.id = "CustomValidator" + validatorName; aValidator.controltovalidate = ""; aValidator.errormessage = "" + invalidateMessage + ""; aValidator.validationGroup = validationGroup; aValidator.initialvalue = ""; aValidator.evaluationfunction = function () { var isValid = false; for (var i = 0; i < attributeNameArray.length; ++i) { if (isValid) { break; } isValid = EntityFormUX.ValidateCheckboxHasChecked(attributeNameArray[i]); } return isValid; }; // Add the new validator to the page validators array Page_Validators.push(aValidator); }, RemoveCustomValidator: function(validatorName) { var validatorId = "CustomValidator" + validatorName; for (i = 0; i < Page_Validators.length; i++) { if (Page_Validators[i].id == validatorId) { // toggle Validator ValidatorEnable(Page_Validators[i], false); return true; } } return false; }, AddCustomValidator: function(attributeName, validatorName, invalidateMessage, validationGroup, validatingFunction) { if (typeof (Page_Validators) == 'undefined') return; if (validationGroup == null) { validationGroup = ""; } var validatorId = "CustomValidator" + validatorName; var isValidatorExist = false; for (i = 0; i < Page_Validators.length; i++) { if (Page_Validators[i].id == validatorId) { ValidatorEnable(Page_Validators[i], true); isValidatorExist = true; break; } } // Don't need to add validator again if (isValidatorExist) return; var aValidator = document.createElement('span'); aValidator.style.display = "none"; aValidator.id = validatorId; aValidator.controltovalidate = "attributeName"; aValidator.errormessage = "" + invalidateMessage + ""; aValidator.validationGroup = validationGroup; aValidator.initialvalue = ""; aValidator.evaluationfunction = validatingFunction; // Add the new validator to the page validators array Page_Validators.push(aValidator); }, ValidateTextboxHasValue: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var attributeControl = $("#" + attributeName); return (attributeControl.val() != null && attributeControl.val().trim() != ""); }, ValidateLookupControlHasValue: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var attributeControl = $("#" + attributeName); return (attributeControl.val() != null && attributeControl.val() != ""); }, ValidateOptionSetDropdownHasSelectedValue: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var attributeControl = $("#" + attributeName); return (attributeControl.val() != null && attributeControl.val() != ""); }, ValidateOptionSetRadioHasSelectedValue: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var checkedValue = ($("#" + attributeName + " input[name$='" + attributeName + "']:checked").val()); var isChecked = checkedValue != undefined; return isChecked; }, // 2 options has value regardless. // This is to check if the checkbox is checked. If not checked, then it is invalid ValidateCheckboxHasChecked: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var attributeControl = $("#" + attributeName); return attributeControl.attr("checked"); }, ValidateDateTimeHasValue: function (attributeName) { if (EntityFormUX.IsControlHidden(attributeName)) return true; var attributeControl = $("#" + attributeName); return (attributeControl.val() != null && attributeControl.val() != ""); }, // Just don't ever call this on change of Postal Code field, cause it overwrites value on match. ValidateCanadianPostalCode: function (attributeName, expect7Characters) { var value = $('#' + attributeName).val().trim(); if (value.length === 6 || value.length === 7) { var newvalue = value.toUpperCase(); // Expecting 7 Character In Length for the attributes if (expect7Characters) { if (newvalue.match(/^[A-Z][0-9][A-Z][0-9][A-Z][0-9]$/)) { newvalue = newvalue.substr(0, 3) + " " + newvalue.substr(3, 3); $("#" + attributeName).val(newvalue); return true; } if (newvalue.match(/^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$/)) { $("#" + attributeName).val(newvalue); return true; } } else { if (newvalue.match(/^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$/)) { newvalue = newvalue.substr(0, 3) + newvalue.substr(4, 3); $("#" + attributeName).val(newvalue); return true; } if (newvalue.match(/^[A-Z][0-9][A-Z][0-9][A-Z][0-9]$/)) { $("#" + attributeName).val(newvalue); return true; } } //value not valid return false; } else if (value.trim().length === 0) { // If empty, then allow other validator to validates return true; } else { //value not valid return false; } }, // Extensions... IsJsonString: function(str) { try { JSON.parse(str); } catch (e) { return false; } return true; }, // This is for Subgrid on load, which will also works with Entity List on Load, // Since all subgrid is rendered as an entity list class AddSubgridListOnLoaded: function(subgridSchemaName, functionOnLoad) { if (subgridSchemaName == null || subgridSchemaName.trim() == "") { $(".entity-grid").on("loaded", functionOnLoad); } else { $("#" + subgridSchemaName + " .entity-grid") .on("loaded", functionOnLoad); } }, // This allow adding an Advanced Filter title on top of the Entity List Filter Control InjectCollapsableEntityListMetadataFilter: function(filterTitle) { if (filterTitle == null || filterTitle.trim() == "") { filterTitle = "Advanced Filter"; } var entityListFilterControl = $("#EntityListFilterControl"); if (entityListFilterControl.length > 0) { var parentDiv = entityListFilterControl.parent(); if (!$("#EntityListFilterControl").hasClass("collapse")) { $("#EntityListFilterControl").addClass("collapse"); } $collapseLink = $("") .attr("href", "#EntityListFilterControl") .attr("id", "advance-filter") .attr("data-toggle", "collapse") .attr("style", "text-decoration:none;") .attr("data-target", "#EntityListFilterControl") .attr("class", "entity-form-accordion-toggle") .html(filterTitle); var collapseLinkHtml = $collapseLink; $collapseTitle = $("

") .attr("class", "tab-title") .html(collapseLinkHtml); var collapseTitleHtml = $collapseTitle; parentDiv.prepend(collapseTitleHtml); $("#advance-filter").addClass("collapsed"); var mf = getParameterByName("mf"); if (mf.length > 0) { $("#EntityListFilterControl").collapse("show"); } } }, // File Size Validation OOB Entity Form upload //Check that file is less than 5 MB. Otherwise, display error message. ValidateFileUploadSize: function(maxFileSizeInMB) { var fileSizeExceeded = 0; var filenames = ""; var maxSizeInBytes = maxFileSizeInMB * 1024 * 1024; for (var i = 0; i < this.files.length; i++) { //If there are more than 1 file, create a string of the filenames to alert user. if (this.files.length > 1) { filenames = filenames + this.files[i].name + "\n"; } if (this.files[i].size > maxSizeInBytes) { $('#AttachFileSizeValidatorAttachFile').show(); //If there is only 1 file, output this text. Otherwise, output the second text for multiple files. if (this.files.length == 1) { $('#AttachFileSizeValidatorAttachFile').text("The uploaded file size exceeds the maximum allowed size of " + maxFileSizeInMB + " MB."); } else { $('#AttachFileSizeValidatorAttachFile').text("The uploaded file size of one your files exceeds the maximum allowed size of " + maxFileSizeInMB + " MB."); } $('#AttachFileSizeValidatorAttachFile').css('color', 'red'); $("#AttachFile").val(''); fileSizeExceeded = 1; } } if (fileSizeExceeded == 0) { $('#AttachFileSizeValidatorAttachFile').hide(); } //If there are multiple uploads and all files are below size limit, launch an alert window that displays the filenames. if ((filenames != "") && (fileSizeExceeded == 0)) { // alert("The following files will be uploaded:\n" + filenames + "\nIf any file is incorrect, please browse and select files again."); return true; } return false; }, // conditionValues can be an integer or a string with integer values separated by commas // Based on value of source attribute, if the value matches those specified in valueToShowTargetControl // Then Show the Control. // Optional to Add Required Field Validator to the Target Control // Required Field Validator only works if there is already some validation fields on the form. ShowHideTextBoxByRadioSelection: function(sourceAttributeName, conditionValues, targetControlAttributeName, requiredIfShown, requiredValidationMessage) { var radio_value = $("input[name$='" + sourceAttributeName + "']:checked").val(); // Treat conditions depends on value to compare is string or integer var showControl = false; if (conditionValues === parseInt(conditionValues, 10)) { showControl = radio_value == conditionValues; } else { // It is a string, delimited with a comma var valuesArray = conditionValues.split(','); for (var i = 0; i < valuesArray.length; i++) { var parsedValueFromArray = parseInt(valuesArray[i], 10); showControl = radio_value == parsedValueFromArray; if (showControl) { break; } } } if (showControl) { if (requiredIfShown) { if (requiredValidationMessage == null || requiredValidationMessage == "") { var dependentControlLabel = $("#" + targetControlAttributeName + "_label"); if (dependentControlLabel.length > 0) { requiredValidationMessage = dependentControlLabel.text() + " is a required field."; } } EntityFormUX.AddPageRequiredFieldValidatorsFor(targetControlAttributeName, "textbox", requiredValidationMessage, ""); } EntityFormUX.ShowControlWithLabel(targetControlAttributeName); } else { // Reset Textbox Field Value EntityFormUX.SetTextboxFieldValue(targetControlAttributeName, ""); EntityFormUX.HideControlWithLabel(targetControlAttributeName); if (requiredIfShown) { EntityFormUX.RemovePageRequiredFieldValidatorsFor(targetControlAttributeName); } } return showControl; }, ShowHideRadioButtonListByRadioSelection:function(sourceAttributeName, conditionValues, targetControlAttributeName, requiredIfShown, requiredValidationMessage) { var radio_value = $("input[name$='" + sourceAttributeName + "']:checked").val(); // Treat conditions depends on value to compare is string or integer var showControl = false; if (conditionValues === parseInt(conditionValues, 10)) { showControl = radio_value == conditionValues; } else { // It is a string, delimited with a comma var valuesArray = conditionValues.split(','); for (var i = 0; i < valuesArray.length; i++) { var parsedValueFromArray = parseInt(valuesArray[i], 10); showControl = radio_value == parsedValueFromArray; if (showControl) { break; } } } if (showControl) { if (requiredIfShown) { if (requiredValidationMessage == null || requiredValidationMessage == "") { var dependentControlLabel = $("#" + targetControlAttributeName + "_label"); if (dependentControlLabel.length > 0) { requiredValidationMessage = dependentControlLabel.text() + " is a required field."; } } EntityFormUX.AddPageRequiredFieldValidatorsFor(targetControlAttributeName, "radio", requiredValidationMessage, ""); } EntityFormUX.ShowControlWithLabel(targetControlAttributeName); } else { // Reset Radio Button Field Value EntityFormUX.ResetRadioButtonSelection(targetControlAttributeName); EntityFormUX.HideControlWithLabel(targetControlAttributeName); if (requiredIfShown) { EntityFormUX.RemovePageRequiredFieldValidatorsFor(targetControlAttributeName); } } return showControl; }, ShowHideSectionByRadioSelection: function(sourceAttributeName, conditionValues, targetSectionName) { var radio_value = $("input[name$='" + sourceAttributeName + "']:checked").val(); // Treat conditions depends on value to compare is string or integer var showControl = false; if (conditionValues === parseInt(conditionValues, 10)) { showControl = radio_value == conditionValues; } else { // It is a string, delimited with a comma var valuesArray = conditionValues.split(','); for (var i = 0; i < valuesArray.length; i++) { var parsedValueFromArray = parseInt(valuesArray[i], 10); showControl = radio_value == parsedValueFromArray; if (showControl) { break; } } } if (showControl) { EntityFormUX.ShowSectionByName(targetSectionName); } else { EntityFormUX.HideSectionByName(targetSectionName); } return showControl; }, // Set on Click for Confirm Submit // Whether it were a modal popup button, or custom button which replace the actual saving mechanism of the Entity Form Save // Entity Form default Update button has id of "UpdateButton. Insert Form button is called "InsertButton" SetOnClickForConfirmSubmit: function(entityFormUpdateButtonid, customButtonid) { // From Custom Template var btnConfirmSubmit = $("#" + customButtonid); // From Entity Form var btnUpdateButton = $("#" + entityFormUpdateButtonid); btnConfirmSubmit.attr("onclick", btnUpdateButton.attr("onclick")); }, AddHelpButtonToControl: function(attributeName, helpText) { var collapsableId=attributeName+"_help_button"; var collapsableWidth="60px"; var collapsable="
"+ "

"+helpText+"

"+ ""+ "
"; $("#"+attributeName).after(collapsable); $("#"+collapsableId).on('click', function(e) { e.preventDefault(); var $this = $(this); var $collapse = $this.closest('.collapse-group').find('.collapse'); $collapse.collapse('toggle'); var isExpanded = $collapse.attr("aria-expanded")=="true"; if(isExpanded) { $this.attr("class","fa fa-caret-up"); } else { $this.attr("class","fa fa-caret-down"); } }); }, // To avoid flicker out effect on form load for dependent control, // Use Metadata to put label text as // // Add CSS Class at the Metadata to be "hidden" // This will hide both the control and the label on render, but allow to show the control when needed. RemoveInitialHiddenClassForControl: function(attributeName) { var labelTextDiv = $("#" + attributeName + "_label_text"); var control = $("#" + attributeName); if (labelTextDiv.hasClass("hidden")) { labelTextDiv.removeClass("hidden"); } if (control.hasClass("hidden")) { control.removeClass("hidden"); } }, // USE WITH CAUTION // Must Check that you can actually delete the record // Website Id can be obtain by Liquid Syntax at site as {{ website.id }} // onComplete is the function to call upon success DeleteEntityRecord: function(recordId, entityLogicalName, websiteId, onComplete) { var deleteActionURL = "/_services/entity-grid-delete/" + websiteId; var entityReference = {}; entityReference.LogicalName = entityLogicalName; entityReference.Id = recordId; var url = window.location.protocol + "//" + window.location.host + deleteActionURL; var data = JSON.stringify(entityReference); shell.ajaxSafePost({ type: "POST", contentType: "application/json", url: url, data: data }).done(onComplete); }, // Utility Functions RemoveStyleToClosestTd: function(controlName, cssClassName) { var control = $("#" + controlName); if (control.length > 0) { var closestTd = control.closest("td"); if (closestTd.hasClass(cssClassName)) { closestTd.removeClass(cssClassName); } } }, AddStyleToClosestTd: function(controlName, cssClassName) { var control = $("#" + controlName); if (control.length > 0) { var closestTd = control.closest("td"); if (!closestTd.hasClass(cssClassName)) { closestTd.addClass(cssClassName); } } }, AddStyleToClosestTabColumn: function(controlName, cssClassName) { var control = $("#" + controlName); if (control.length > 0) { var closestTd = control.closest("div.tab-column"); if (!closestTd.hasClass(cssClassName)) { closestTd.addClass(cssClassName); } } }, // Add CSS Class to Section AddClassToSection: function(sectionName, cssClassName) { var sectionTable = $('table[data-name="' + sectionName + '"]'); if (sectionTable.length > 0) { var sectionLegend = sectionTable.parent(); if (sectionLegend.length) { if (!sectionLegend.hasClass(cssClassName)) { sectionLegend.addClass(cssClassName); } } } }, // Remove CSS Class from Section RemoveClassFromSection: function(sectionName, cssClassName) { var sectionTable = $('table[data-name="' + sectionName + '"]'); if (sectionTable.length > 0) { var sectionLegend = sectionTable.parent(); if (sectionLegend.length) { if (sectionLegend.hasClass(cssClassName)) { sectionLegend.removeClass(cssClassName); } } } } } // You should know that Liquid Syntax can be used in Entity Form's Custom Script area // Getting Parameter By Name can be // var paramId = "{{ request.params['id'] }}"; function getParameterByName(name) { var regexS = "[\\?&]" + name + "=([^&#]*)", regex = new RegExp(regexS), results = regex.exec(window.location.search); if (results == null) { return ""; } else { return decodeURIComponent(results[1].replace(/\+/g, " ")); } } // Can be called from an IFrame onload="ResizeIFrameHeight(this);" function ResizeIFrameHeight(iframe) { iframe.height = iframe.contentWindow.document.body.scrollHeight + "px"; } // This allow your event handler to be triggered first... // To Use, datetimePickerTextbox.bindFirst("keydown", function (e) {...}); $.fn.bindFirst = function (name, fn) { var elem, handlers, i, _len; this.bind(name, fn); for (i = 0, _len = this.length; i < _len; i++) { elem = this[i]; handlers = jQuery._data(elem).events[name.split('.')[0]]; handlers.unshift(handlers.pop()); } };