";
jQuery("#bulk_items").prepend(str);
}
}
function SelectCustomChoice( name ){
jQuery("#gfield_bulk_add_input").val(gform_custom_choices[name].join("\n"));
gform_selected_custom_choice = name;
InitBulkCustomPanel();
}
function SelectPredefinedChoice(name){
var list = gform_predefined_choices[name];
// Countries can also be an object if the gform_countries filter is used, so convert to array with just the values.
if( name == "Countries" && Array.isArray( list ) !== true ) {
list = Object.values( list );
}
jQuery('#gfield_bulk_add_input').val(list.join('\n'));
gform_selected_custom_choice = "";
InitBulkCustomPanel();
}
function InsertBulkChoices(choices){
field = GetSelectedField();
field.choices = new Array();
var enableValue = false;
for(var i=0; i 1){
var currency = GetCurrentCurrency();
price = currency.toMoney(text_price[1]);
}
text_value = text_value.split("|");
if(text_value.length > 1)
enableValue = true;
choice = new Choice(jQuery.trim(text_value[0]), jQuery.trim(text_value[text_value.length -1]), jQuery.trim(price));
/**
* Filter each individual Choice object as it is inserted into the UI.
*
* This filter is generally used in combination with gform_load_bulk_choices_choice, and is useful
* for parsing a unique text pattern (e.g., Label|Value|Other) and adding the additional data to
* the resulting Choice object.
*
* @since 2.5
*
* @param {Choice} choice The Choice object representing this particular Choice data.
* @param {string} choice_string The string representing the current choice as a text pattern.
* @param {object} field The current field being evaluated.
*
* @return {Choice} The updated Choice object containing any additional data needed.
*/
choice = gform.applyFilters( 'gform_insert_bulk_choices_choice', choice, choices[i], field );
if ( FieldIsChoiceType( field ) ) {
InsertFieldForChoice( choice, field );
}
field.choices.push( choice );
}
/**
* Fires after bulk choices have been added to the field object and before the UI has been re-rendered.
*
* This action is useful if you need to alter other field settings based on the choices.
*
* @since 2.3
*
* @param array field The currently selected field object.
*/
gform.doAction( 'gform_bulk_insert_choices', field );
if(enableValue){
field["enableChoiceValue"] = true;
jQuery('#field_choice_values_enabled').prop("checked", true);
ToggleChoiceValue();
}
LoadFieldChoices(field);
RefreshSelectedFieldPreview();
}
function InitBulkCustomPanel(){
if(gform_selected_custom_choice.length == 0){
CloseCustomChoicesPanel();
}
else{
LoadCustomChoicesPanel();
}
}
function LoadCustomChoicesPanel(isNew, speed){
if(isNew){
jQuery("#custom_choice_name").val("");
jQuery("#bulk_save_button").html(gf_vars.save);
jQuery("#bulk_cancel_link").show();
jQuery("#bulk_delete_link").hide();
}
else{
jQuery("#custom_choice_name").val(gform_selected_custom_choice);
jQuery("#bulk_save_button").html(gf_vars.update);
jQuery("#bulk_cancel_link").hide();
jQuery("#bulk_delete_link").show();
}
jQuery("#bulk_save_as").hide();
jQuery("#bulk_custom_edit").show();
}
function CloseCustomChoicesPanel(){
jQuery("#bulk_save_as").show();
jQuery("#bulk_custom_edit").hide();
}
function IsEmpty(array){
var key;
for (key in array) {
if (array.hasOwnProperty(key))
return false;
}
return true;
}
function SetFieldChoice(inputType, index, refresh = true){
var text = jQuery("#" + inputType + "_choice_text_" + index).val();
var value = jQuery("#" + inputType + "_choice_value_" + index).val();
var price = jQuery("#" + inputType + "_choice_price_" + index).val();
field = GetSelectedField();
fieldBeforeUpdate = field;
field.choices[index].text = text;
field.choices[index].value = field.enableChoiceValue ? value : text;
if(field.enablePrice){
var currency = GetCurrentCurrency();
var price = currency.toMoney(price);
if(!price)
price = "";
field.choices[index]["price"] = price;
}
//set field selections
jQuery("#field_choices :radio, #field_choices :checkbox").each(function(index){
field.choices[index].isSelected = this.checked;
});
ToggleClearDefaultChoicesButton();
LoadBulkChoices(field);
if ( refresh ) {
RefreshSelectedFieldPreview();
}
// Checkbox field inputs are re-generated on the fly.
// For Choice field inputs, we need to update the input directly to keep the same IDs.
if ( FieldIsChoiceType( field ) ) {
let input = GetInputFromKey(field.choices[index].key, field);
input.label = text;
}
}
function ResetDefaultChoices() {
jQuery( '#field_choices' ).find( ':radio, :checkbox' ).each( function( index, element ) {
var id = element.id;
var inputType = id.split( '_' )[0];
var index = id.split( '_' ).pop();
jQuery( element ).prop( 'checked', false );
SetFieldChoice( inputType, index, false );
} );
RefreshSelectedFieldPreview();
}
function ToggleClearDefaultChoicesButton() {
var clearDefaultButton = jQuery( '.field-choice-clear-default' );
if ( jQuery( '#field_choices :radio:checked, #field_choices :checkbox:checked' ).length ) {
clearDefaultButton.show();
} else {
clearDefaultButton.hide();
}
}
function SetInputChoice(inputId, index, value, text){
var field = GetSelectedField();
var input = GetInput(field, inputId);
inputId = inputId.toString().replace('.', '_');
input.choices[index].text = text;
input.choices[index].value = input.enableChoiceValue ? value : text;
//set field selections
jQuery(".field-input-choice-" + inputId + ":radio, .field-input-choice-" + inputId + ":checkbox").each(function(index){
input.choices[index].isSelected = this.checked;
});
UpdateInputChoices(input);
}
/*
* Deprecated in 2.9.0
*/
function UpdateFieldChoices(fieldType){
console.log( 'UpdateFieldChoices is deprecated as of Gravity Forms 2.9.0 and will be removed in a future version. Please use RefreshSelectedFieldPreview instead.' );
var choices = '';
var selector = '';
var inputContainer = ( "1" === gf_legacy.is_legacy ) ? 'li' : 'div';
var inputContainerClass;
if(field.inputType == "checkbox")
field.inputs = new Array();
var skip = 0;
// Multiselect is functionally just a select input with a different attribute; adjust the type here.
if ( fieldType === 'multiselect' ) {
fieldType = 'select';
}
switch( fieldType ){
case "select" :
for(var i=0; i" + field.choices[i].text + "";
}
break;
case "checkbox" :
for(var i=0; i" + inputContainer + ">";
}
}
if(field.choices.length > 5)
choices += "<" + inputContainer + " class='gchoice_total'>" + gf_vars["editToViewAll"].replace("%d", field.choices.length) + "" + inputContainer + ">";
if ( field.enableSelectAll ) {
choices += '';
}
break;
case "radio" :
for(var i=0; i" + inputContainer + ">";
}
}
choices += field.enableOtherChoice ? "<" + inputContainer + ">" + inputContainer + ">" : "";
if(field.choices.length > 5) {
choices += "<" + inputContainer + " class='gchoice_total'>" + gf_vars["editToViewAll"].replace("%d", field.choices.length) + "" + inputContainer + ">";
}
break;
case "list" :
RefreshSelectedFieldPreview();
break;
}
selector = '.gfield_' + fieldType;
jQuery(".field_selected " + selector).html(choices);
}
function UpdateInputChoices(input){
var choices = '';
for(var i=0; i" + input.choices[i].text + "";
}
var inputId = input.id.toString().replace('.', '_');
jQuery(".field_selected #input_" + inputId).html(choices);
}
function InsertFieldChoice( index ) {
field = GetSelectedField();
var inputType = GetInputType( field );
var text = "";
var value = "";
var price = field[ "enablePrice" ] ? "0.00" : "";
var file_url = "";
if ( inputType === 'list' ) {
text = window.gf_vars.column + " " + (index + 1);
value = window.gf_vars.column + " " + (index + 1);
}
var newChoice = new Choice( text, value, price );
if ( window[ "gform_new_choice_" + field.type ] ) {
newChoice = window[ "gform_new_choice_" + field.type ]( field, newChoice );
}
if ( typeof field.choices !== 'object' ) {
field.choices = [];
}
field.choices.splice( index, 0, newChoice );
if ( FieldIsChoiceType( field ) ) {
InsertFieldForChoice( newChoice, field );
}
LoadFieldChoices( field );
RefreshSelectedFieldPreview();
}
/**
* Generate a new input for a choice field and set a new ID by increasing the last input ID.
*
* @since 2.9
*
*/
function InsertFieldForChoice( newChoice, field ) {
// Checkbox field inputs are generated on the fly.
// For Choice field inputs, we need to manually generate the input and set a new ID by increasing the last input ID.
// This works because the inputs array is never reordered and the higher ID inputs are always appended to the end of the array.
newChoice.key = GenerateUniqueFieldKey();
var inputId = field.id + '.1';
if ( ! Array.isArray( field.inputs ) ) {
field.inputs = [];
} else {
//get last input id number
var newInputNumber = parseInt(field.inputs[ field.inputs.length - 1 ].id.split( '.' )[1]);
newInputNumber++;
// increment lastInputId if its multiple of ten
if ( newInputNumber % 10 === 0 ) {
newInputNumber++;
}
inputId = field.id + '.' + newInputNumber;
}
var input = new Input(inputId, newChoice.text);
input.key = newChoice.key;
field.inputs.push(input);
}
/**
* Generates a new random key for a field input.
*
* @since 2.9
*
*/
function GenerateUniqueFieldKey() {
return Math.random().toString(36).substring(2, 11) + Date.now().toString(36);
}
/**
* Get the matching input object from the choices array based on the key.
*
* @since 2.9
*
* @param key
* @param field
*/
function GetInputFromKey( key, field ) {
var input = false;
if ( !field ) {
field = GetSelectedField();
}
if ( Array.isArray( field.inputs ) ) {
field.inputs.forEach( function( fieldInput ) {
if ( fieldInput.key === key ) {
input = fieldInput;
}
} );
}
return input;
}
function InsertInputChoice($ul, inputId, index){
var field = GetSelectedField();
var input = GetInput(field, inputId);
var new_choice = new Choice("", "");
input.choices.splice(index, 0, new_choice);
LoadInputChoices($ul, input);
UpdateInputChoices(input);
}
async function DeleteFieldChoice(index){
field = GetSelectedField();
var value = jQuery('#' + GetInputType(field) + '_choice_value_' + index).val();
var hasDependency = await HasConditionalLogicDependency(field.id, value);
if( hasDependency ) {
var message = gf_vars.conditionalLogicDependencyChoice.replace('{type}', hasDependency);
gform.instances.dialogConfirmAsync( gf_vars.conditionalLogicWarningTitle , message ).then( ( confirmed ) => {
if ( ! confirmed ) {
return;
}
RemoveFieldChoice(index, field);
});
} else {
RemoveFieldChoice(index, field);
}
}
/**
* Removes the selected item from the field choices.
*
* @since 2.9
*
* @param {int} index The index of the choice to remove.
* @param {(object|boolean)} field The value returned from the jQuery Selector.
*/
function RemoveFieldChoice(index, field){
// For Checkbox field, inputs are re-generated on the fly.
// For Choice fields, we need to manually find and delete the matching input.
if ( FieldIsChoiceType( field ) ) {
var key = field.choices[index].key;
field.choices.splice(index, 1);
var input = GetInputFromKey( key, field );
if ( input ) {
var index = field.inputs.indexOf( input );
field.inputs.splice( index, 1 );
}
} else {
field.choices.splice(index, 1);
}
LoadFieldChoices(field);
RefreshSelectedFieldPreview();
}
function DeleteInputChoice($ul, inputId, index){
var field = GetSelectedField();
var input = GetInput(field, inputId);
input.choices.splice(index, 1);
LoadInputChoices($ul, input);
UpdateInputChoices(input);
}
function MoveFieldChoice(fromIndex, toIndex){
field = GetSelectedField();
var choice = field.choices[fromIndex];
//deleting from old position
field.choices.splice(fromIndex, 1);
//inserting into new position
field.choices.splice(toIndex, 0, choice);
LoadFieldChoices(field);
RefreshSelectedFieldPreview();
}
function MoveInputChoice($ul, inputId, fromIndex, toIndex){
var field = GetSelectedField();
var input = GetInput(field, inputId);
var choice = input.choices[fromIndex];
//deleting from old position
input.choices.splice(fromIndex, 1);
//inserting into new position
input.choices.splice(toIndex, 0, choice);
LoadInputChoices($ul, input);
UpdateInputChoices(input);
}
function GetFieldType(fieldId){
return fieldId.substr(0, fieldId.lastIndexOf("_"));
}
function GetSelectedField() {
var $field = jQuery( '.field_selected' );
if( $field.length <= 0 ) {
return false;
}
var id = $field[0].id.substr( 6 );
return GetFieldById( id );
}
function SetPasswordProperty(isChecked){
SetFieldProperty("enablePasswordInput", isChecked);
}
function ToggleDateCalendar( isInit ){
var dateType = jQuery("#field_date_input_type").val();
if(dateType == "datefield" || dateType == "datedropdown"){
jQuery("#date_picker_container").hide();
SetCalendarIconType("none");
}
else{
jQuery("#date_picker_container").show();
}
}
function ToggleCalendarIconUrl( isInit ){
if(jQuery("#gsetting_icon_custom").is(":checked")){
jQuery("#gfield_icon_url_container").show();
}
else{
jQuery("#gfield_icon_url_container").hide();
jQuery("#gfield_calendar_icon_url").val("");
SetFieldProperty('calendarIconUrl', '');
}
}
function SetTimeFormat(format){
SetFieldProperty('timeFormat', format);
LoadTimeInputs();
}
function LoadTimeInputs(){
var field = GetSelectedField();
if(field.type != 'time' && field.inputType != 'time'){
return;
}
var format = jQuery("#field_time_format").val();
if(format == "24"){
jQuery('#input_default_value_row_input_' + field.id +'_3').hide();
jQuery(".field_selected .gfield_time_ampm").hide();
} else {
jQuery('#input_default_value_row_input_' + field.id +'_3').show();
jQuery(".field_selected .gfield_time_ampm").show();
}
jQuery('#input_placeholder_row_input_' + field.id +'_3').hide(); // No support for placeholder.
// AM/PM Sub label is hidden in the time field class after `gform_post_load_field_settings` is fired.
}
/**
* Set date format for a date field.
*
* @since unknown
* @since 2.5 Updated for the layout editor.
*
* @param format
* @constructor
*/
function SetDateFormat( format ) {
SetFieldProperty( 'dateFormat', format );
var field = GetSelectedField();
if ( field.dateType === 'datepicker' ) {
var formatLabel = jQuery( '#field_date_format option:selected' ).text();
if ( field.placeholder === '' ) {
jQuery( '.field_selected input[name="ginput_datepicker"]' )
.attr( 'placeholder', formatLabel );
}
}
RefreshSelectedFieldPreview();
}
function SetCalendarIconType(iconType, isInit){
field = GetSelectedField();
if(GetInputType(field) != "date")
return;
if(iconType == undefined)
iconType = "calendar";
// The "none" option was removed in 3.0, so all fields with the "none" value are set to "calendar" to maintain backwards compatibility.
if(iconType == "none" || iconType == "calendar") {
jQuery( "#gsetting_icon_calendar" ).prop( "checked", true );
jQuery( "#gfield_icon_url_container" ).hide();
} else if(iconType == "custom") {
jQuery( "#gsetting_icon_custom" ).prop( "checked", true );
jQuery( "#gfield_icon_url_container" ).show();
}
SetFieldProperty('calendarIconType', iconType);
ToggleCalendarIconUrl( isInit );
if ( ! isInit ) {
RefreshSelectedFieldPreview();
}
}
function SetDateInputType(type){
field = GetSelectedField();
if(GetInputType(field) != "date")
return;
field.dateType = type;
field.inputs = GetDateFieldInputs(field);
CreateDefaultValuesUI(field);
CreatePlaceholdersUI(field);
CreateInputLabelsUI(field);
ToggleDateSettings(field);
ToggleDateCalendar();
ResetDefaultInputValues(field);
RefreshSelectedFieldPreview();
}
function SetPostImageMeta(){
var displayAlt = jQuery('#gfield_display_alt').is(":checked");
var displayTitle = jQuery('#gfield_display_title').is(":checked");
var displayCaption = jQuery('#gfield_display_caption').is(":checked");
var displayDescription = jQuery('#gfield_display_description').is(":checked");
var displayLabel = (displayAlt || displayTitle || displayCaption || displayDescription);
//setting property
SetFieldProperty('displayAlt', displayAlt);
SetFieldProperty('displayTitle', displayTitle);
SetFieldProperty('displayCaption', displayCaption);
SetFieldProperty('displayDescription', displayDescription);
//updating UI
jQuery('.field_selected .ginput_post_image_alt').css("display", displayAlt ? "block" : "none");
jQuery('.field_selected .ginput_post_image_title').css("display", displayTitle ? "block" : "none");
jQuery('.field_selected .ginput_post_image_caption').css("display", displayCaption ? "block" : "none");
jQuery('.field_selected .ginput_post_image_description').css("display", displayDescription ? "block" : "none");
jQuery('.field_selected .ginput_post_image_file').css("display", displayLabel ? "block" : "none");
}
function SetFeaturedImage() {
var isChecked = jQuery('#gfield_featured_image').is(':checked');
if(isChecked) {
for(i in form.fields) {
if(!form.fields.hasOwnProperty(i))
continue;
form.fields[i].postFeaturedImage = false;
}
SetFieldProperty('postFeaturedImage', true);
}
else{
SetFieldProperty('postFeaturedImage', false);
}
}
function SetFieldProperty(name, value){
if (value == undefined)
value = "";
var field = GetSelectedField();
var previousValue = rgar( field, name );
field[name] = value;
/**
* Enables custom actions to be performed when a field property is set.
*
* @since 2.7.16
*
* @param {string} name The name of the property that was set.
* @param {object} field The field object that was updated.
* @param {(string|number|boolean|array)} value The current value of the specified property.
* @param {(string|number|boolean|array)} previousValue The previous value of the specified property.
*/
window.gform.doAction( 'gform_post_set_field_property', name, field, value, previousValue );
}
function SetInputName(value, inputId){
var field = GetSelectedField();
if(value)
value = value.trim();
if(!inputId){
field["inputName"] = value;
}
else{
for(var i=0; i b["text"].toLowerCase() );});
}
function SetFieldLabel(label){
var existingLabel = jQuery( ".field_selected.gfield--type-repeater > .gfield-admin-wrapper > .gfield_repeater_wrapper > .gfield_repeater_container > .gform-field-label .gform-field-label__text, .field_selected:not(.gfield--type-repeater) label.gfield_label .gform-field-label__text, .field_selected:not(.gfield--type-repeater) .gsection_title, .field_selected:not(.gfield--type-repeater) legend.gfield_label .gform-field-label__text" );
var requiredElement = existingLabel.find(".gfield_required")[0]
existingLabel.text(label).append(requiredElement);
SetFieldProperty("label", label);
var nativeEvent = new Event('gform/form_editor/set_field_label');
document.dispatchEvent(nativeEvent);
}
/**
* Set the Aria Label for a field in the editor.
*
* @since 2.5.
*
* @param {string} label The field label
*/
function SetAriaLabel(label){
var fieldId = jQuery( ".field_selected" )[0].id.split( '_' )[1];
var field = GetFieldById( fieldId );
var ariaLabel = window.gf_vars.fieldLabelAriaLabel.replace('{field_label}', label).replace('{field_type}', field.type);
jQuery( ".field_selected .gfield-edit" ).attr( 'aria-label', ariaLabel );
}
function SetCaptchaTheme(theme, thumbnailUrl){
jQuery(".field_selected .gfield_captcha").attr("src", thumbnailUrl);
SetFieldProperty("captchaTheme", theme);
}
function SetCaptchaSize(size){
var type = jQuery("#field_captcha_type").val();
SetFieldProperty("simpleCaptchaSize", size);
RedrawCaptcha();
jQuery(".field_selected .gfield_captcha_input_container").removeClass(type + "_small").removeClass(type + "_medium").removeClass(type + "_large").addClass(type + "_" + size);
}
function SetCaptchaFontColor(color){
SetFieldProperty("simpleCaptchaFontColor", color);
RedrawCaptcha();
}
function SetCaptchaBackgroundColor(color){
SetFieldProperty("simpleCaptchaBackgroundColor", color);
RedrawCaptcha();
}
function RedrawCaptcha(){
var captchaType = jQuery("#field_captcha_type").val();
if(captchaType == "math"){
url_1 = GetCaptchaUrl(1);
url_2 = GetCaptchaUrl(2);
url_3 = GetCaptchaUrl(3);
jQuery(".field_selected .gfield_captcha:eq(0)").attr("src", url_1);
jQuery(".field_selected .gfield_captcha:eq(1)").attr("src", url_2);
jQuery(".field_selected .gfield_captcha:eq(2)").attr("src", url_3);
}
else{
url = GetCaptchaUrl();
jQuery(".field_selected .gfield_captcha").attr("src", url);
}
}
function SetFieldEnhancedUI( checked ) {
SetFieldProperty( 'enableEnhancedUI', checked ? 1 : 0 );
if ( checked ) {
SetFieldAccessibilityWarning( 'enable_enhanced_ui_setting', 'above' );
} else {
resetAllFieldAccessibilityWarnings();
}
}
function SetFieldSize(size) {
jQuery(".field_selected .small, .field_selected .medium, .field_selected .large").removeClass("small").removeClass("medium").removeClass("large").addClass(size);
var field = GetSelectedField();
if ( field.type == 'textarea' ) {
delete field.size;
SetFieldProperty("textareaHeight", size);
} else {
SetFieldProperty("size", size);
}
}
function SetFieldLabelPlacement(labelPlacement) {
var labelPlacementClass = labelPlacement ? labelPlacement : form.labelPlacement;
SetFieldProperty("labelPlacement", labelPlacement);
jQuery(".field_selected").removeClass("top_label").removeClass("right_label").removeClass("left_label").removeClass("hidden_label").addClass(labelPlacementClass);
if ((field.labelPlacement == 'left_label' || field.labelPlacement == 'right_label' || (field.labelPlacement == '' && form.labelPlacement != 'top_label'))) {
jQuery('#field_description_placement').val('');
SetFieldProperty("descriptionPlacement", '');
jQuery('#field_description_placement_container').hide();
} else {
jQuery('#field_description_placement_container').show();
}
if (field.labelPlacement == 'hidden_label') {
SetFieldAccessibilityWarning('label_placement_setting', 'above');
} else {
resetAllFieldAccessibilityWarnings();
}
SetFieldProperty("labelPlacement", labelPlacement);
SetFieldRequired(field.isRequired);
RefreshSelectedFieldPreview();
}
function SetFieldDescriptionPlacement(descriptionPlacement){
SetFieldProperty("descriptionPlacement", descriptionPlacement);
RefreshSelectedFieldPreview();
}
function SetFieldSubLabelPlacement( subLabelPlacement ) {
SetFieldProperty( "subLabelPlacement", subLabelPlacement );
RefreshSelectedFieldPreview();
}
async function SetFieldVisibility( visibility, handleInputs, isInit ) {
var hasDependency = await HasConditionalLogicDependency(field.id);
if (!isInit && visibility === 'administrative' && hasDependency) {
var message = gf_vars.conditionalLogicDependencyAdminOnly.replace('{type}', hasDependency);
gform.instances.dialogConfirmAsync(gf_vars.conditionalLogicWarningTitle , message).then((confirmed) => {
if (confirmed) {
proceedWithVisibilityChange(visibility, handleInputs);
} else {
proceedWithVisibilityChange( 'visible', true );
}
});
} else {
proceedWithVisibilityChange(visibility, handleInputs);
}
}
function proceedWithVisibilityChange( visibility, handleInputs ) {
const isWhitelisted = gf_vars.visibilityOptions.some(option => option.value === visibility);
if( ! isWhitelisted ) {
visibility = 'visible';
}
SetFieldProperty( 'visibility', visibility );
if( handleInputs ) {
const $inputs = jQuery('input[name="field_visibility"]');
$inputs.prop( 'checked', false );
$inputs.filter( '[value="' + visibility + '"]' ).prop( 'checked', true );
}
}
function SetFieldDefaultValue(defaultValue){
jQuery(".field_selected > div > input:visible, .field_selected > div > textarea:visible, .field_selected > div > select:visible").val(defaultValue);
SetFieldProperty('defaultValue', defaultValue);
}
function SetFieldPlaceholder(placeholder){
jQuery(".field_selected > div > input:visible, .field_selected > div > textarea:visible, .field_selected > div > select:visible").each(function(){
var type = this.nodeName;
var $this = jQuery(this);
if(type == 'INPUT' || type == 'TEXTAREA'){
jQuery(this).prop("placeholder", placeholder);
} else if (type == 'SELECT'){
var $option = $this.find('option[value=""]');
if($option.length>0){
if(placeholder.length > 0){
$option.text(placeholder);
} else {
$option.remove();
}
} else {
$this.prepend('');
$this.val('');
}
}
});
SetFieldProperty('placeholder', placeholder);
}
function SetFieldDescription(description){
if(description == undefined)
description = "";
SetFieldProperty('description', description);
}
function SetFieldCheckboxLabel(text){
if(text == undefined)
text = "";
SetFieldProperty('checkboxLabel', text);
}
function SetFieldCheckboxInputs(field) {
// this function generates the inputs for checkboxes that are not part of a choice field
if ( ! [ 'checkbox' ].includes( GetInputType( field ) ) || FieldIsChoiceType( field ) ) {
return
}
field.inputs = new Array();
var skip = 0;
for(var i=0; i span, label.gfield_label, .gform-field-label__text' );
labelElement = Array.from( labelCandidates ).find( function( el ) {
return el.closest( '.gfield' ) === selectedField;
} );
} else if ( field.type === 'consent' && field.labelPlacement === 'hidden_label' ) {
labelElement = selectedField.querySelector( '.gfield_consent_label' );
} else {
labelElement = selectedField.querySelector( 'legend.gfield_label > span, label.gfield_label' );
}
if ( labelElement ) {
labelElement.insertAdjacentHTML( 'beforeend', '' + requiredIndicatorHtml + '' );
}
}
SetFieldProperty( 'isRequired', isRequired );
}
function SetMaxLength(input) {
var patt = GetMaxLengthPattern();
var cleanValue = '';
var characters = input.value.split('');
for(i in characters) {
if(!characters.hasOwnProperty(i))
continue;
if( !patt.test(characters[i]) )
cleanValue += characters[i];
}
input.value = cleanValue;
SetFieldProperty('maxLength', cleanValue);
}
function GetMaxLengthPattern() {
return /[a-zA-Z\-!@#$%^&*();'":_+=<,>.~`?\/|\[\]\{\}\\]/;
}
/**
* Validate any keypress events based on a provided RegExp.
*
* Function retrieves the character code from the keypress event and tests it against provided pattern.
* Optionally specify 'matchPositive' argument to false in order to return true if the character is NOT
* in the provided pattern.
*
* @param event The JS keypress event.
* @param patt RegExp to test keypress character against.
* @param matchPositive Defaults to true. Whether to return true if the character is found or NOT found in the pattern.
*/
function ValidateKeyPress(event, patt, matchPositive) {
var matchPositive = typeof matchPositive == 'undefined' ? true : matchPositive;
var char = event['which'] ? event.which : event.keyCode;
var isMatch = patt.test(String.fromCharCode(char));
if(event.ctrlKey)
return true;
return matchPositive ? isMatch : !isMatch;
}
function IndexOf(ary, item){
for(var i=0; i' );
$submitImageSetting.val( src );
}
}
//------------------------------------------------------------------------------------------------------------------------
//Color Picker
function iColorShow(mouseX, mouseY, id, callback){
jQuery("#iColorPicker").css({'top': (mouseY - 150) +"px",'left':mouseX +"px",'position':'absolute'}).fadeIn("fast");
jQuery("#iColorPickerBg").css({'position':'absolute','top':0,'left':0,'width':'100%','height':'100%'}).fadeIn("fast");
var def=jQuery("#"+id).val();
jQuery('#colorPreview span').text(def);
jQuery('#colorPreview').css('background',def);
jQuery('#color').val(def);
var hxs=jQuery('#iColorPicker');
for(i=0;i
').appendTo("body");jQuery(document.createElement("div")).attr("id","iColorPickerBg").click(function(){jQuery("#iColorPickerBg").hide();jQuery("#iColorPicker").fadeOut()}).appendTo("body");jQuery('table.pickerTable td').css({'width':'12px','height':'14px','border':'1px solid #000','cursor':'pointer'});jQuery('#iColorPicker table.pickerTable').css({'border-collapse':'collapse'});jQuery('#iColorPicker').css({'border':'1px solid #ccc','background':'#333','padding':'5px','color':'#fff','z-index':9999})}
jQuery('#colorPreview').css({'height':'50px'});
})
};
jQuery(function(){iColorPicker()});
function SetColorPickerColor(field_name, color, callback){
var chip = jQuery('#chip_' + field_name);
chip.css("background-color", color);
if(callback)
window[callback](color);
}
jQuery( document ).mouseup( function( e ) {
var container = jQuery( "#iColorPicker" );
if ( ! container.is( e.target ) && container.has( e.target ).length === 0 ) {
jQuery( "#iColorPickerBg" ).hide();
jQuery( "#iColorPicker" ).fadeOut();
}
} );
function SetFieldChoices(){
var field = GetSelectedField();
for(var i=0; i {
$container = jQuery( '.field_selected .field-sidebar-message-content--type-' + type );
messageMarkup = $container && $container.length ? gform_strip_scripts( $container.html() ) : '';
if ( messageMarkup ) {
jQuery( '#sidebar_field_message_container' ).html( '
' );
jQuery( '#sidebar_field_message_container .gform-alert__message' ).html( messageMarkup );
jQuery( '#sidebar_field_message_container .gform-alert' ).addClass( 'gform-alert--' + ( type === 'warning' ? 'error' : type ) );
iconClasses.forEach(
( className ) => {
jQuery( '#sidebar_field_message_container .gform-alert__icon' ).addClass( className );
}
);
// Add class to force this notice visible, as all field notices are reset when a field is selected.
if ( type === 'notice' ) {
jQuery( '#sidebar_field_message_container .gform-alert' ).addClass( 'gform-visible-notice' );
}
showSidebarMessage = true;
wp.a11y.speak( messageMarkup );
} else {
jQuery( '#sidebar_field_message_container' ).hide();
}
}
);
if ( showSidebarMessage ) {
jQuery( '#sidebar_field_message_container' ).show();
jQuery( '#sidebar_field_message_container .gform-alert' ).show();
}
}
/**
* Set the field error for a field settings.
*
* We add the field setting to the "errors" field property and display the error
* message next to the setting.
*
* @since 2.5
*
* @param {string} fieldSetting The field setting class name.
* @param {string} position The position to put the warning, can be 'above' or 'below'.
* @param {string} [message] The message to be set in the warning.
*/
function setFieldError( fieldSetting, position, message ) {
var field = GetSelectedField();
// Make sure this field can have errors.
if ( field.type == 'page' ||
field.type == 'section' ||
field.type == 'html' ) {
return;
}
var errorProperties = [ fieldSetting ];
// Extra rules for the label setting.
if ( fieldSetting === 'label_setting' ) {
var fieldPlaceholder = field.hasOwnProperty( 'placeholder' ) ? field.placeholder : '';
var fieldDescription = field.hasOwnProperty( 'description' ) ? field.description : '';
if ( fieldPlaceholder !== '' || fieldDescription !== '' ) {
SetFieldAccessibilityWarning( 'label_setting', 'below' );
resetFieldError( 'label_setting' );
return;
} else {
ResetFieldAccessibilityWarning( 'label_setting' );
}
}
// Set up error property list to the "errors" property.
if ( field.hasOwnProperty( 'errors' ) && ! field.errors.includes( fieldSetting ) ) {
errorProperties = errorProperties.concat( field.errors );
}
SetFieldProperty( 'errors', errorProperties );
// Get the error message.
if ( message === undefined ) {
message = getFieldErrorMessage( fieldSetting );
}
var errorDiv = '
';
errorDiv += '';
errorDiv += '
' + message + '
';
errorDiv += '
';
// Display the error message.
var fieldSettingContainer = jQuery( '.' + fieldSetting );
fieldSettingContainer.addClass( 'error' );
jQuery( '.gform-alert--error[data-field-setting="' + fieldSetting + '"]' ).remove();
if ( position === 'above' ) {
fieldSettingContainer.before( errorDiv );
} else {
fieldSettingContainer.after( errorDiv );
}
}
/**
* Reset the field error for a field setting.
*
* @since 2.5
*
* @param {string} [fieldSetting] The field setting class name.
*/
function resetFieldError( fieldSetting ) {
var field = GetSelectedField();
var errorProperties = field.hasOwnProperty( 'errors' ) ? field.errors : [];
if ( typeof fieldSetting !== 'undefined' ) {
jQuery( '.gform-alert--error[data-field-setting="' + fieldSetting + '"]' ).remove()
jQuery( '.' + fieldSetting ).removeClass( 'error' );
var index = errorProperties.indexOf( fieldSetting );
// Delete the field property from the errors.
if ( index > -1 ) {
if ( errorProperties.length > 1 ) {
delete errorProperties[ index ];
} else {
errorProperties = [];
}
}
}
SetFieldProperty( 'errors', errorProperties );
}
/**
* Reset the field errors for all field settings.
*
* @since 2.5.8
*/
function resetAllFieldErrors() {
if ( ! jQuery( '.field_setting' ).hasClass( 'error' ) ) {
return;
}
jQuery('.editor-sidebar .gform-alert--error').remove();
jQuery('.field_setting').filter('.error').removeClass( 'error' );
if ( form.fields.length > 0 ) {
form.fields.forEach( function( field ) {
if( field.hasOwnProperty( 'errors' ) && field.errors.length > 0 ) {
field.errors = [];
}
} );
}
}
/**
* Check if a given field or the selected field has errors.
*
* @since 2.5
*
* @param {object} [field] The field object.
*
* @return {boolean}
*/
function fieldHasError( field ) {
if ( typeof field === 'undefined' ) {
field = GetSelectedField();
}
if ( field.hasOwnProperty( 'errors' ) && field.errors.length > 0 ) {
return true;
}
return false;
}
/**
* Recursively searches for a field by ID and returns it with its parent object.
*
* @since 3.0
*
* @param {Object} parent The object that contains the fields array to search.
* @param {number} fieldId The field ID to find.
*
* @return {Object|null} An object containing the found field and its parent, or null.
*/
function findFieldAndParentRecursively( parent, fieldId ) {
if ( ! parent || ! Array.isArray( parent.fields ) ) {
return null;
}
for ( let i = 0; i < parent.fields.length; i++ ) {
const field = parent.fields[ i ];
// Use a Yoda condition for strict equality checks.
if ( fieldId === field.id ) {
return {
field,
index: i,
parent,
parentArray: parent.fields,
};
}
// Recurse into repeaters.
if ( 'repeater' === field.type ) {
const found = findFieldAndParentRecursively( field, fieldId );
if ( found ) {
return found;
}
}
}
return null;
}
/**
* Toggles the visibility of phone field settings based on phone format.
*
* @since Unknown
* @access public
*
* @param {object} field The field object.
*
* @return void
*/
function TogglePhoneSettings(field) {
var phoneFormat = field.phoneFormat || 'standard';
var isInternationalFormatted = phoneFormat === 'formatted';
// Hide placeholder setting for international (formatted) format
jQuery('.placeholder_setting').toggle(!isInternationalFormatted);
jQuery('.size_setting').toggle(!isInternationalFormatted);
// Show default country settings and sub-labels settings only for international (formatted) format
jQuery('.default_country_setting').toggle(isInternationalFormatted);
jQuery('.show_country_code_setting').toggle(isInternationalFormatted);
jQuery('.phone_sub_labels_setting').toggle(isInternationalFormatted);
if (isInternationalFormatted) {
var showCountryCode = field.showCountryCode !== undefined ? field.showCountryCode : true;
jQuery('#field_show_country_code').prop('checked', showCountryCode);
PopulateCountryDropdown(field);
jQuery('#field_custom_input_label_countrySublabel').val(field.countrySublabel || '');
jQuery('#field_custom_input_label_phoneSublabel').val(field.phoneSublabel || '');
}
}
/**
* Populate the country dropdown with all available countries.
*
* @since Unknown
* @param {object} field The field object.
* @return void
*/
function PopulateCountryDropdown(field) {
var $select = jQuery('#field_default_country');
// Check if already populated
if ($select.find('option').length > 1) {
// Always set to field's defaultCountry or 'us' if empty
var valueToSet = field.defaultCountry || 'us';
$select.val(valueToSet);
UpdateCountryFlag($select);
return;
}
var countries = [];
// Convert from object with uppercase codes to array with lowercase codes
for (var countryCode in gf_vars.defaultCountries) {
if (gf_vars.defaultCountries.hasOwnProperty(countryCode)) {
countries.push({
iso: countryCode.toLowerCase(),
name: gf_vars.defaultCountries[countryCode]
});
}
}
jQuery.each(countries, function(index, country) {
var $option = jQuery('')
.attr('value', country.iso)
.text(country.name);
$select.append($option);
});
// Pre-select US if no country is set
$select.val(field.defaultCountry || 'us');
// Update flag display
UpdateCountryFlag($select);
// Update flag on change
$select.off('change.flag').on('change.flag', function() {
UpdateCountryFlag(jQuery(this));
});
}
/**
* Update the flag display for the selected country.
*
* @since Unknown
* @param {jQuery} $select The select element.
* @return void
*/
function UpdateCountryFlag($select) {
var selectedCountry = $select.val() || 'us'; // Default to US if no country selected
var $wrapper = $select.closest('.gform-phone-country-select-wrapper');
var $flag = $wrapper.find('.gform-phone-country-flag');
// Update the flag classes
// Remove all country-specific classes
$flag.attr('class', function(i, className) {
return className.replace(/gform-phone__flag-icon--\w+/g, '');
});
// Add the base class and the new country class
$flag.addClass('gform-phone__flag-icon--' + selectedCountry);
}
/**
* Listen for phone format changes and toggle settings accordingly.
*
* @since Unknown
*/
gform.addAction('gform_post_set_field_property', function(name, field, value, previousValue) {
if (name === 'phoneFormat') {
TogglePhoneSettings(field);
RefreshSelectedFieldPreview();
}
});