: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// Set layout to inline on activation, revert to one column on deactivation.
$fieldOptions.find( `#wpforms-field-option-${ fieldID }-input_columns` ).val( checked ? 'inline' : '' ).trigger( 'change' );
// Finally, update the preview.
app.fieldChoiceUpdate( $fieldOptions.find( '.wpforms-field-option-hidden-type' ).val(), fieldID );
* Change accent color and update previews.
fieldID = $this.parents( '.wpforms-field-option-row' ).data( 'field-id' ),
$field = $( '#wpforms-field-option-' + fieldID ),
type = $field.find( '.wpforms-field-option-hidden-type' ).val(),
$choicesList = $field.find( '.wpforms-field-option-row-choices .choices-list' ),
colorValue = app.getValidColorPickerValue( $this );
// Update icons color in options panel.
$choicesList.prop( 'style', `${ app.iconChoices.config.colorPropertyName }: ${ colorValue };` );
app.fieldChoiceUpdate( type, fieldID );
* Open a modal prompting to install the icon library for Icon Choices.
* @param {boolean} force Whether it's a normal installation procedure or forced if the library is needed but is missing.
openInstallPromptModal( force = false ) {
? wpforms_builder.icon_choices.strings.reinstall_prompt_content
: wpforms_builder.icon_choices.strings.install_prompt_content;
const modal = $.confirm( {
title: wpforms_builder.heads_up,
icon: 'fa fa-info-circle',
text: wpforms_builder.continue,
this.setIcon( 'fa fa-cloud-download' );
this.setTitle( wpforms_builder.icon_choices.strings.install_title );
this.setContent( wpforms_builder.icon_choices.strings.install_content );
$.each( this.buttons, function( _index, button ) {
app.iconChoices.installIconLibrary();
// Do not close the modal.
// Turn the toggle off during normal installation.
if ( ! force && app.iconChoices.cache.toggle ) {
app.iconChoices.cache.toggle.prop( 'checked', false );
app.iconChoices.cache.previousModal = this;
// Add a Cancel button for normal installation routine only.
text: wpforms_builder.cancel,
app.iconChoices.cache.toggle.prop( 'checked', false );
* Silently download and install the icon library on the server.
// eslint-disable-next-line camelcase
_wp_http_referer: wpf.updateQueryString( '_wp_http_referer', null ),
nonce: wpforms_builder.nonce,
action: 'wpforms_icon_choices_install',
timeout: 120000, // 2 minutes.
$.post( wpforms_builder.ajax_url, data, function( response ) {
// eslint-disable-next-line no-unused-expressions
? app.iconChoices.openInstallSuccessModal()
: app.iconChoices.openInstallErrorModal( response );
} ).fail( function( jqXHR ) {
app.iconChoices.openInstallErrorModal( jqXHR );
* Open a modal on icon library installation success.
openInstallSuccessModal() {
title: wpforms_builder.done,
content: wpforms_builder.icon_choices.strings.install_success_content,
icon: 'fa fa-check-circle',
text: wpforms_builder.ok,
if ( app.iconChoices.cache.toggle ) {
app.iconChoices.cache.toggle.prop( 'checked', true );
const fieldId = app.iconChoices.cache.toggle.parents( '.wpforms-field-option-row' ).data( 'field-id' );
const $imageChoices = $builder.find( `#wpforms-field-option-${ fieldId }-choices_images` );
// Turn Image Choice off, if needed, without triggering change event.
if ( $imageChoices.is( ':checked' ) ) {
$imageChoices.prop( 'checked', false );
app.formSave( false ).done( function() {
window.location.reload();
if ( app.iconChoices.cache.toggle ) {
const fieldId = app.iconChoices.cache.toggle.parents( '.wpforms-field-option-row-choices_icons' ).data( 'field-id' );
$builder.find( `#wpforms-field-option-${ fieldId }-input_columns` ).val( 'inline' );
app.iconChoices.cache.previousModal.close();
* Open a modal on icon library installation failure.
* @param {Object} errorData Unsuccessful ajax JSON response or jqXHR object.
openInstallErrorModal( errorData ) {
title: wpforms_builder.uh_oh,
content: wpforms_builder.icon_choices.strings.install_error_content,
icon: 'fa fa-exclamation-circle',
text: wpforms_builder.ok,
if ( app.iconChoices.cache.toggle ) {
app.iconChoices.cache.toggle.prop( 'checked', false );
app.iconChoices.cache.previousModal.close();
// Clean up the cache, we're done.
delete app.iconChoices.cache.previousModal;
delete app.iconChoices.cache.toggle;
* Extend jquery-confirm plugin with support of max-height for the content area.
// Extend a method of global instance.
window.Jconfirm.prototype._updateContentMaxHeight = function() { // noinspection JSUnusedGlobalSymbols
const height = $( window ).height() - ( this.$jconfirmBox.outerHeight() - this.$contentPane.outerHeight() ) - ( this.offsetTop + this.offsetBottom );
// Custom property, if set via jquery-confirm options.
const maxHeight = this.contentMaxHeight || height;
'max-height': Math.min( maxHeight, height ) + 'px',
* Open Icon Picker modal.
fieldId: $this.parents( '.wpforms-field-option-row' ).data( 'field-id' ),
choiceId: $this.parent().data( 'key' ),
selectedIcon: $this.find( '.source-icon' ).val(),
selectedIconStyle: $this.find( '.source-icon-style' ).val(),
${ wpforms_builder.icon_choices.strings.icon_picker_title }
<span class="wpforms-icon-picker-description">${ wpforms_builder.icon_choices.strings.icon_picker_description }</span>
<input type="text" placeholder="${ wpforms_builder.icon_choices.strings.icon_picker_search_placeholder }" class="search" id="wpforms-icon-picker-search">
<div class="wpforms-icon-picker-container" id="wpforms-icon-picker-icons">
<ul class="wpforms-icon-picker-icons" data-field-id="${ data.fieldId }" data-choice-id="${ data.choiceId }"></ul>
<ul class="wpforms-icon-picker-pagination"></ul>
<p class="wpforms-icon-picker-not-found wpforms-hidden" data-message="${ wpforms_builder.icon_choices.strings.icon_picker_not_found }"></>
titleClass: 'wpforms-icon-picker-title',
contentMaxHeight: 368, // Custom property, see app.iconChoices.extendJqueryConfirm().
// Add custom classes to target various elements.
this.$body.addClass( 'wpforms-icon-picker-jconfirm-box' );
this.$contentPane.addClass( 'wpforms-icon-picker-jconfirm-content-pane' );
// Initialize the list of icons with List.js and display the 1st page.
app.iconChoices.initIconsList( data );
// Focus the search input.
modal.$title.find( '.search' ).focus();
// Listen for clicks on icons to select them.
modal.$content.find( '.wpforms-icon-picker-icons' ).on( 'click', 'li', function() {
app.iconChoices.selectIcon( modal, $( this ) );
* Initialize List.js in the Icon Selector modal on demand and cache it.
* @param {Object} data Source option data - field and choice IDs, selected icon name and style.
listClass: 'wpforms-icon-picker-icons',
page: wpforms_builder.icon_choices.icons_per_page,
paginationClass: 'wpforms-icon-picker-pagination',
const maybeSelectedClass = ( values.icon === data.selectedIcon && values.style === data.selectedIconStyle ) ? 'class="selected"' : '';
<li data-icon="${ values.icon }" data-icon-style="${ values.style }"${ maybeSelectedClass }>
<i class="ic-fa-${ values.style } ic-fa-${ values.icon }"></i>
<span class="name">${ values.icon }</span>
// Initialize List.js instance.
const iconsList = new List( 'wpforms-icon-picker-icons', options, wpforms_builder.icon_choices.icons );
// Initialize infinite scroll pagination on the list instance.
app.iconChoices.infiniteScrollPagination( iconsList );
// Bind search to custom input.
$( '#wpforms-icon-picker-search' ).on( 'keyup', function() {
// Custom partial match search.
iconsList.search( $( this ).val(), [ 'name' ], function( searchString, columns ) { // eslint-disable-line no-unused-vars
for ( let index = 0, length = iconsList.items.length; index < length; index++ ) {
iconsList.items[ index ].found = ( new RegExp( searchString ) ).test( iconsList.items[ index ].values().icon );
// Show "nothing found" message if the search returned no results.
iconsList.on( 'searchComplete', function() {
const $element = $( '.wpforms-icon-picker-not-found' );
$element.html( $element.data( 'message' ).replace( '{keyword}', $( '#wpforms-icon-picker-search' ).val() ) );
$element.toggleClass( 'wpforms-hidden', ! _.isEmpty( iconsList.matchingItems ) );
* Handle infinite scroll on the list of icons.
* @param {Object} list List.js instance.
infiniteScrollPagination( list ) {
root: document.querySelector( '.wpforms-icon-picker-jconfirm-content-pane' ),
rootMargin: '600px', // 5 rows of icons. Formula: 20 + ( (96 + 20) * rows ).
const observer = new IntersectionObserver( function( entries ) {
if ( ! entries[ 0 ].isIntersecting ) {
list.show( 0, page * wpforms_builder.icon_choices.icons_per_page );
observer.observe( document.querySelector( '.wpforms-icon-picker-pagination' ) );
* When an icon is selected, update the choice and the field preview.
* @param {Object} modal Current jQuery Confirm modal instance.
* @param {jQuery} $this The list item (icon) that was clicked.
selectIcon( modal, $this ) {
const fieldId = $this.parent().data( 'field-id' );
const choiceId = $this.parent().data( 'choice-id' );
const icon = $this.data( 'icon' );
const iconStyle = $this.data( 'icon-style' );
const $choice = $( '#wpforms-field-option-row-' + fieldId + '-choices ul li[data-key=' + choiceId + ']' );
const fieldType = $( '#wpforms-field-option-row-' + fieldId + '-choices ul' ).data( 'field-type' );
$this.addClass( 'selected' );
$this.siblings( '.selected' ).removeClass( 'selected' );
$choice.find( '.wpforms-icon-select span' ).text( icon );
$choice.find( '.wpforms-icon-select .ic-fa-preview' ).removeClass().addClass( `ic-fa-preview ic-fa-${ iconStyle } ic-fa-${ icon }` );
$choice.find( '.wpforms-icon-select .source-icon' ).val( icon );
$choice.find( '.wpforms-icon-select .source-icon-style' ).val( iconStyle );
app.fieldChoiceUpdate( fieldType, fieldId );
//--------------------------------------------------------------------//
//--------------------------------------------------------------------//
* Click on the Dismiss notice button.
$builder.on( 'click', '.wpforms-alert-field-not-available .wpforms-dismiss-button', function( e ) {
const $button = $( this ),
$alert = $button.closest( '.wpforms-alert' ),
fieldId = $button.data( 'field-id' );
$alert.addClass( 'out' );
$( '#wpforms-field-option-' + fieldId ).remove();
//--------------------------------------------------------------------//
//--------------------------------------------------------------------//
const $title = $( '.wpforms-center-form-name' );
if ( $title.text().length > 38 ) {
const shortTitle = $title.text().trim().substring( 0, 38 ).split( ' ' ).slice( 0, -1 ).join( ' ' ) + '...';
$title.text( shortTitle );
* Load or refresh color picker.
* @since 1.7.9 Added default value support.
$( '.wpforms-color-picker' ).each( function() {
// If it appears to be already initialized, reset. This is needed when duplicating fields with color pickers.
if ( $this.hasClass( 'minicolors-input' ) ) {
$this.minicolors( 'destroy' );
defaultValue: $this.data( 'fallback-color' ) || '',
* Get a valid color value from color picker or a default one.
* @param {Object} $colorPicker Current field.
* @return {string} Always valid color value.
getValidColorPickerValue( $colorPicker ) {
const color = $colorPicker.minicolors( 'value' );
// jQuery MiniColors returns "black" RGB object if the color value is invalid.
const isInvalid = _.isEqual( $colorPicker.minicolors( 'rgbObject' ), { r: 0, g: 0, b: 0 } );
const isBlack = _.includes( [ '#000', '#000000' ], color );
// If default value isn't provided via the data attribute, use black.
const defaultValue = $colorPicker.data( 'fallback-color' ) || '#000000';
return isInvalid && ! isBlack ? defaultValue : color;
* Ctrl+/ - Keyboard Shortcuts modal.
* Ctrl+F - Focus search fields input.
* Ctrl+T - Toggle sidebar.
$( document ).on( 'keydown', function( e ) { // eslint-disable-line complexity