File: /home/globfdxw/www/wp-content/plugins/wpforms-pdf/assets/js/modules/custom.js
/* global WPForms, wpformsPDF, wpforms_builder, WPFormsPDFBuilder, wpf */
/**
* @function getValue
* @function setChoices
* @param choices._store
* @param wpformsPDF.customTemplates
* @param templateData.appearance
* @param themeData.colors
* @param wpforms_builder.pdf.theme.delete_title
* @param wpforms_builder.pdf.theme.delete_confirm
* @param wpforms_builder.pdf.theme.delete_cant_undone
* @param wpforms_builder.pdf.theme.delete_yes
* @param wpforms_builder.pdf.template.delete_title
* @param wpforms_builder.pdf_template.delete_confirm
*/
/**
* WPForms PDF: Custom templates/themes module.
*
* @since 1.0.0
*
* @param {Object} document Document object.
* @param {Object} window Window object.
* @param {jQuery} $ jQuery object.
*
* @return {Object} Public functions and properties.
*/
export default function( document, window, $ ) { // eslint-disable-line no-unused-vars, max-lines-per-function
/**
* Elements holder.
*
* @since 1.0.0
*
* @type {Object}
*/
const el = {};
/**
* Public functions and properties.
*
* @since 1.0.0
*/
const app = {
/**
* Altered theme data.
*
* @since 1.0.0
*
* @type {Object|null}
*/
alteredThemeData: null,
/**
* Initialize module.
*
* @since 1.0.0
*/
init() {
app.setup();
app.initAllCustomEntitiesSettings();
app.bindEvents();
},
/**
* Setup. Prepare some variables.
*
* @since 1.0.0
*/
setup() {
// Cache DOM elements.
el.$builder = $( '#wpforms-builder' );
// Create a debounced function to update entity data.
app.updateEntityDataAjaxDebounced = _.debounce( app.updateEntityDataAjax, 200 );
},
/**
* Bind events.
*
* @since 1.0.0
*/
bindEvents() {
el.$builder
.on( 'click', '.wpforms-pdf-custom-entity-rename', app.clickRename )
.on( 'click', '.wpforms-pdf-custom-entity-delete', app.clickDelete )
.on( 'click', '.wpforms-pdf-custom-entity-name-save', app.clickRenameSaveButton )
.on( 'click', '.wpforms-pdf-custom-entity-name-cancel', app.clickRenameCancelButton )
.on( 'wpformsSaved', app.wpformsSaved )
.on( 'wpformsPDFReflectorElementUpdate', app.reflectorElementUpdate )
.on( 'wpformsSettingsBlockAdded wpformsSettingsBlockCloned', app.pdfAdded )
.on( 'input', '.wpforms-field-pdf-custom-entity-name-field input', app.entityNameChanged )
.on( 'change', '.wpforms-pdf-template-category select', app.toggleCustomEntityVisibility )
.on( 'change', '.wpforms-pdf-template-style select', app.toggleCustomEntityVisibility )
.on( 'change', '.wpforms-pdf-theme-selector select', app.toggleCustomEntityVisibility );
},
/**
* The PDF block was added or cloned.
*
* @since 1.0.0
*
* @param {Event} e The event object.
* @param {jQuery} $block The block element.
*/
pdfAdded( e, $block ) {
if ( $block.data( 'block-type' ) !== 'pdf' ) {
return;
}
app.initAllCustomEntitiesSettings( $block );
},
/**
* Initialize all custom entities' settings.
*
* @since 1.0.0
*
* @param {jQuery} $block The block element.
*/
initAllCustomEntitiesSettings( $block ) {
$block = $block?.length ? $block : el.$builder;
$block.find( '.wpforms-pdf-custom-entity-settings' ).each( function() {
app.initCustomEntitySettings( $( this ) );
} );
},
/**
* Initialize custom entity settings.
*
* @since 1.0.0
*
* @param {jQuery} $settings Settings element object.
*/
initCustomEntitySettings( $settings ) {
if ( ! $settings?.length ) {
return;
}
const entity = $settings.data( 'entity' );
const value = $settings.prev( '.wpforms-panel-field-select' ).find( 'select' ).val();
const data = entity === 'theme' ? app.getThemeData( value ) : app.getTemplateData( value );
const isCustom = data?.isCustom ?? false;
const $field = $settings.find( '.wpforms-field-pdf-custom-entity-name-field' );
$settings.toggleClass( 'wpforms-hidden', ! isCustom );
$field.addClass( 'wpforms-hidden' );
},
/**
* Get the current template for the given pdfId.
*
* @since 1.0.0
*
* @param {string} pdfId Template slug.
*
* @return {string} Template slug.
*/
getCurrentTemplateSlug( pdfId ) {
return $( `#wpforms-panel-field-pdfs-${ pdfId }-template_style` ).val();
},
/**
* Get the current theme for the given pdfId.
*
* @since 1.0.0
*
* @param {string} pdfId Template slug.
*
* @return {string} Theme slug.
*/
getCurrentThemeSlug( pdfId ) {
return $( `#wpforms-panel-field-pdfs-${ pdfId }-theme` ).val();
},
/**
* Get the template data.
*
* @since 1.0.0
*
* @param {string} slug Template slug.
*
* @return {Object|null} Template data.
*/
getTemplateData( slug ) {
return WPFormsPDFBuilder.templates.getTemplateData( slug );
},
/**
* Get the theme data.
*
* @since 1.0.0
*
* @param {string} slug Theme slug.
*
* @return {Object|null} Theme data.
*/
getThemeData( slug ) {
return WPFormsPDFBuilder.appearance.getThemeData( slug );
},
/**
* Toggle custom entity settings visibility.
*
* @since 1.0.0
*
* @param {Event} e Event object.
* @param {jQuery} $select The select element, optional.
*/
toggleCustomEntityVisibility( e, $select ) {
$select = $select ?? $( this );
const $settings = $select.closest( '.wpforms-panel-field' ).nextAll( '.wpforms-pdf-custom-entity-settings' );
const entity = $settings.data( 'entity' );
const value = $select.val();
const data = entity === 'theme' ? app.getThemeData( value ) : app.getTemplateData( value );
const isCustom = data?.isCustom ?? false;
$settings.toggleClass( 'wpforms-hidden', ! isCustom );
},
/**
* Handle entity name change.
*
* @since 1.0.0
*/
entityNameChanged() {
const $input = $( this );
const $saveBtn = $input.closest( '.wpforms-field-pdf-custom-entity-name-field' ).find( '.wpforms-pdf-custom-entity-name-save' );
$saveBtn.toggleClass( 'wpforms-disabled', ! $input.val() );
},
/**
* Click rename an action link.
*
* @since 1.0.0
*
* @param {Event} e Event object.
*/
clickRename( e ) {
const $button = $( this );
const $settings = $button.closest( '.wpforms-pdf-custom-entity-settings' );
const $select = $settings.prevAll( '.wpforms-pdf-template-style, .wpforms-pdf-theme-selector' ).find( 'select' );
const $field = $settings.find( '.wpforms-field-pdf-custom-entity-name-field' );
const currentName = $select.find( 'option:selected' ).text();
$field
.removeClass( 'wpforms-hidden' )
.find( 'input' )
.val( currentName );
e.preventDefault();
},
/**
* Click delete action link.
*
* @since 1.0.0
*
* @param {Event} e Event object.
*/
clickDelete( e ) {
const $this = $( this );
const $settings = $this.closest( '.wpforms-pdf-custom-entity-settings' );
const $select = $settings.prevAll( '.wpforms-pdf-template-style, .wpforms-pdf-theme-selector' ).find( 'select' );
const entity = $settings.data( 'entity' );
app.openEntityDeleteModal( $select, entity );
e.preventDefault();
},
/**
* Click the rename save button.
*
* @since 1.0.0
*
* @param {Event} e Event object.
*/
clickRenameSaveButton( e ) {
const $button = $( this );
const $settings = $button.closest( '.wpforms-pdf-custom-entity-settings' );
const $field = $button.closest( '.wpforms-field-pdf-custom-entity-name-field' );
const $input = $field.find( 'input' );
const $select = $settings.prevAll( '.wpforms-pdf-template-style, .wpforms-pdf-theme-selector' ).find( 'select' );
const entity = $settings.data( 'entity' );
const entityName = $input.val();
const entitySlug = $select.val();
let entityData = {};
$select
.find( 'option:selected' )
.text( entityName );
// Update ChoicesJS option.
if ( entity === 'theme' ) {
app.updateThemeSelectorItem( entitySlug, entityName );
wpformsPDF.customThemes[ entitySlug ].title = entityName;
entityData = app.getThemeData( entitySlug );
}
if ( entity === 'template' ) {
wpformsPDF.customTemplates[ entitySlug ].title = entityName;
entityData = app.getTemplateData( entitySlug );
}
app.updateEntityData( entityData, entity );
$field.addClass( 'wpforms-hidden' );
e.preventDefault();
},
/**
* Click the rename cancel button.
*
* @since 1.0.0
*
* @param {Event} e Event object.
*/
clickRenameCancelButton( e ) {
const $button = $( this );
const $field = $button.closest( '.wpforms-field-pdf-custom-entity-name-field' );
$field.addClass( 'wpforms-hidden' );
e.preventDefault();
},
/**
* The `wpformsPDFReflectorElementUpdate` event handler.
*
* @since 1.0.0
*
* @param {Event} e Event object.
* @param {Object} reflectorElement Reflector element data object.
*/
reflectorElementUpdate( e, reflectorElement ) {
if ( reflectorElement.context === 'triggered' ) {
return;
}
const templateSlug = app.getCurrentTemplateSlug( reflectorElement.pdfId );
const templateData = app.getTemplateData( templateSlug );
const themeData = app.getThemeData( reflectorElement.themeSlug );
if ( ! templateData || ! themeData ) {
return;
}
if ( app.detectThemeAlternate( reflectorElement, themeData, templateData ) ) {
app.processThemeAlternate( templateData, reflectorElement.themeSlug, themeData, reflectorElement.themeColorKey, reflectorElement );
return;
}
if ( app.detectTemplateAlternate( reflectorElement, templateData ) ) {
app.processTemplateAlternate( templateData, reflectorElement );
}
},
/**
* Detect theme modification.
*
* @since 1.0.0
*
* @param {Object} reflectorElement Reflector element data object.
* @param {Object} themeData Theme data object.
* @param {Object} templateData Template data object.
*
* @return {boolean} `true` if theme modification detected, `false` otherwise.
*/
detectThemeAlternate( reflectorElement, themeData, templateData ) { // eslint-disable-line complexity
const isThemeColorChange = reflectorElement.isThemeColorChange &&
themeData.colors?.[ reflectorElement.themeColorKey ] !== reflectorElement.value;
if ( isThemeColorChange ) {
return true;
}
const appearance = {
...templateData.appearance,
...( themeData.appearance ?? {} ),
};
const isAppearanceChange = appearance[ reflectorElement.setting ] !== undefined &&
appearance[ reflectorElement.setting ] !== reflectorElement.value;
if ( isAppearanceChange ) {
return true;
}
return templateData.text[ reflectorElement.setting ] &&
reflectorElement.setting.includes( '_color' ) &&
templateData.text[ reflectorElement.setting ] !== reflectorElement.value;
},
/**
* Detect template modification.
*
* @since 1.0.0
*
* @param {Object} reflectorElement Reflector element data object.
* @param {Object} templateData Template data object.
*
* @return {boolean} `true` if template modification detected, `false` otherwise.
*/
detectTemplateAlternate( reflectorElement, templateData ) {
const rawTemplateValue = templateData.text?.[ reflectorElement.setting ];
const templateValue = app.decodeHTMLEntities( rawTemplateValue ?? '' );
return typeof rawTemplateValue !== 'undefined' && // It is a text template setting
! reflectorElement.setting.includes( '_color' ) && // It is not a color setting
templateValue !== reflectorElement.value; // The value is changed.
},
/**
* Decode HTML entities.
*
* @since 1.0.0
*
* @param {string} html Encoded HTML string.
*
* @return {string} Decoded HTML string.
*/
decodeHTMLEntities( html ) {
const txt = document.createElement( 'textarea' );
txt.innerHTML = html;
return txt.value;
},
/**
* Create a new unique slug.
*
* @since 1.0.0
*
* @param {string} baseSlug Base slug to create a new unique slug from.
* @param {string} entity Entity type, `theme` or `template`.
*
* @return {string} New unique slug.
*/
getNewSlug( baseSlug, entity ) {
// Start with the original slug.
let newSlug = baseSlug;
const data = entity === 'theme' ? wpformsPDF.customThemes : wpformsPDF.customTemplates;
do {
// Generate a hash based on the current timestamp.
const hash = Math.floor( Date.now() / 1000 );
newSlug = `${ baseSlug }-copy-${ hash }`;
} while ( data?.[ newSlug ] );
return newSlug;
},
/**
* Get the copy number.
*
* @since 1.0.0
*
* @param {string} baseSlug Base slug to create a new unique slug from.
* @param {string} entity Entity type, `theme` or `template`.
*
* @return {number} Number of theme copies.
*/
getCopyNumber( baseSlug, entity ) {
const data = Object.values( entity === 'theme' ? wpformsPDF.customThemes : wpformsPDF.customTemplates );
const key = entity === 'theme' ? 'baseTheme' : 'baseTemplate';
// Count all themes where baseTheme matches the provided parameter.
if ( ! data.length ) {
return 0;
}
const count = data.filter( ( entityData ) => {
return entityData[ key ] === baseSlug;
} )?.length;
return count + 1;
},
/**
* Get the entity copy title.
*
* @since 1.0.0
*
* @param {number} copyNumber Copy number.
* @param {Object} data Entity data.
*
* @return {string} New copy title.
*/
getCopyTitle( copyNumber, data ) {
return copyNumber > 1
? `${ data.title } (Copy ${ copyNumber })`
: `${ data.title } (Copy)`;
},
/**
* AJAX call to update/delete the entity data.
*
* @since 1.0.0
*
* @param {Object} entityData Theme data object.
* @param {string} entity Entity type, `theme` or `template`.
*/
updateEntityData( entityData, entity ) {
if ( ! entityData || ! entity ) {
return;
}
app.updateEntityDataAjaxDebounced( entityData, entity );
},
/**
* Queue update theme data.
*
* @since 1.0.0
*
* @param {Object} themeData Theme data object.
*/
queueUpdateThemeData( themeData ) {
app.alteredThemeData = themeData;
},
/**
* The `wpformsSaved` event handler.
*
* @since 1.0.0
*/
wpformsSaved() {
if ( app.alteredThemeData ) {
app.updateEntityDataAjax( app.alteredThemeData, 'theme' );
app.alteredThemeData = null;
}
},
/**
* AJAX call to update/delete the entity data.
*
* @since 1.0.0
*
* @param {Object} entityData Theme data object.
* @param {string} entity Entity type, `theme` or `template`.
*/
updateEntityDataAjax( entityData, entity ) {
if ( ! entityData || ! entityData.slug ) {
return;
}
entity = entity === 'theme' ? entity : 'template';
// Prepare data for AJAX request.
const data = {
action: `wpforms_pdf_update_${ entity }_data`,
nonce: wpforms_builder.nonce,
data: entityData,
};
const errorMessage = entity.charAt( 0 ).toUpperCase() + entity.slice( 1 ) + ' update error';
// Make the AJAX call.
$.post( wpforms_builder.ajax_url, data )
.done( function( response ) {
if ( ! response.success ) {
wpf.debug( errorMessage, response );
}
} )
.fail( function( xhr, textStatus ) {
wpf.debug( errorMessage, xhr.responseText || textStatus || '' );
} );
},
/**
* Open the delete theme confirmation modal.
*
* @since 1.0.0
*
* @param {jQuery} $select The select element.
* @param {string} entity Entity name.
*/
openEntityDeleteModal( $select, entity ) {
const strings = wpforms_builder.pdf[ entity ];
const name = $select?.find( 'option:selected' ).text();
const confirm = strings.delete_confirm.replace( '%1$s', `<b>${ name }</b>` );
const content = `<p class="wpforms-entity-delete-text">${ confirm } ${ wpforms_builder.pdf.theme.delete_cant_undone }</p>`;
$.confirm( {
title: strings.delete_title,
content,
icon: 'fa fa-exclamation-circle wpforms-exclamation-circle',
type: 'red',
buttons: {
confirm: {
text: wpforms_builder.pdf.theme.delete_yes,
btnClass: 'btn-confirm',
keys: [ 'enter' ],
action() {
if ( entity === 'theme' ) {
app.deleteTheme( $select );
}
if ( entity === 'template' ) {
app.deleteTemplate( $select );
}
// Hide Rename | Delete buttons.
app.toggleCustomEntityVisibility( {}, $select );
},
},
cancel: {
text: wpforms_builder.cancel,
keys: [ 'esc' ],
},
},
} );
},
/**
* -------- Theme processing functions. --------
*/
/**
* Process theme change.
*
* @since 1.0.0
*
* @param {Object} templateData Theme data object.
* @param {string} themeSlug Theme slug.
* @param {Object} themeData Theme data object.
* @param {string} themeColorKey Theme color key.
* @param {Object} reflectorElement Reflector element data object.
*/
processThemeAlternate( templateData, themeSlug, themeData, themeColorKey, reflectorElement ) {
if ( ! themeSlug || ! themeData || ! reflectorElement ) {
return;
}
// When the theme is not custom, we should first create the custom theme.
if ( ! themeData.isCustom ) {
themeData = app.createNewTheme( templateData, themeSlug, themeData, themeColorKey, reflectorElement );
} else {
themeData = app.updateThemeData( templateData, themeSlug, themeColorKey, reflectorElement );
}
// Update theme data.
app.queueUpdateThemeData( themeData );
// When the theme color is not changed, we should do nothing.
if ( ! reflectorElement.isThemeColorChange ) {
return;
}
// Update color swatch in the theme selectors.
app.updateThemeSelectorColorSwatch( themeData, themeColorKey, reflectorElement.value );
// Apply theme changes.
WPFormsPDFBuilder.appearance.applyThemeChanges( $( `#wpforms-panel-field-pdfs-${ reflectorElement.pdfId }-theme` ) );
},
/**
* Create a new custom theme.
*
* @since 1.0.0
*
* @param {Object} templateData Theme data object.
* @param {string} themeSlug Theme slug.
* @param {Object} themeData Theme data object.
* @param {string} themeColorKey Theme color key.
* @param {Object} reflectorElement Reflector element data object.
*
* @return {Object} New theme data.
*/
createNewTheme( templateData, themeSlug, themeData, themeColorKey, reflectorElement ) {
const newSlug = app.getNewSlug( themeSlug, 'theme' );
const copyNumber = app.getCopyNumber( themeSlug, 'theme' );
const newTitle = app.getCopyTitle( copyNumber, themeData );
// Create new theme data.
const newThemeData = {
colors: { ...themeData.colors },
title: newTitle,
appearance: { ...themeData.appearance ?? {} },
text: {},
isCustom: true,
slug: newSlug,
baseTheme: themeSlug,
};
// The default theme in Notifications should have appearance colors inherited from the global Email settings.
if ( templateData.category === 'notification' && themeSlug === wpformsPDF.defaultTheme ) {
newThemeData.appearance = { ...themeData.emailAppearance, ...newThemeData.appearance };
}
wpformsPDF.customThemes[ newSlug ] = newThemeData;
app.updateThemeData( templateData, newSlug, themeColorKey, reflectorElement );
app.addThemeSelectorItem( newThemeData, reflectorElement );
// Trigger theme change.
$( `#wpforms-panel-field-pdfs-${ reflectorElement.pdfId }-theme` ).trigger( 'change' );
return newThemeData;
},
/**
* Update the theme data.
*
* @since 1.0.0
*
* @param {Object} templateData Theme data object.
* @param {string} themeSlug Theme slug.
* @param {string} themeColorKey Theme color key.
* @param {Object} reflectorElement Reflector element data object.
* @param {string} newTitle New title, optional.
*
* @return {Object|null} Theme data.
*/
updateThemeData( templateData, themeSlug, themeColorKey, reflectorElement, newTitle = '' ) { // eslint-disable-line complexity
const themeData = app.getThemeData( themeSlug );
// When the theme is not custom, we should do nothing.
if ( ! themeData || ! themeData.isCustom ) {
return null;
}
const value = reflectorElement.value ?? '';
// Store color setting from the template text OR appearance sections.
if ( templateData.text[ reflectorElement.setting ] ) {
themeData.text = themeData.text ?? {};
themeData.text[ reflectorElement.setting ] = value;
} else {
themeData.appearance = themeData.appearance ?? {};
themeData.appearance[ reflectorElement.setting ] = value;
}
// Store color setting from the theme colors editor.
if ( reflectorElement.isThemeColorChange ) {
themeData.colors[ themeColorKey ] = value;
}
// Update title.
if ( newTitle ) {
themeData.title = newTitle;
}
wpformsPDF.customThemes[ themeSlug ] = themeData;
return themeData;
},
/**
* Update the theme selector item.
*
* @since 1.0.0
*
* @param {string} themeSlug Theme slug.
* @param {string} newName New theme name.
*/
updateThemeSelectorItem( themeSlug, newName ) {
$( '.wpforms-pdf-theme-selector select' ).each( function() {
const $select = $( this );
const choices = $select?.data( 'choicesjs' );
if ( ! choices ) {
return;
}
const updatedChoices = choices._store.choices.map( ( choice ) => {
if ( choice.value === themeSlug ) {
return { ...choice, label: newName };
}
return choice;
} );
app.updateThemeSelectorChoices( choices, updatedChoices );
} );
},
/**
* Add a new theme to the theme selector.
*
* @since 1.0.0
*
* @param {Object} themeData Theme data.
* @param {Object} reflectorElement Reflector element data object.
*/
addThemeSelectorItem( themeData, reflectorElement ) {
$( '.wpforms-pdf-theme-selector select' ).each( function() {
const $select = $( this );
const choices = $select?.data( 'choicesjs' );
if ( ! choices ) {
return;
}
const updatedChoices = choices._store.choices;
updatedChoices.unshift( {
value: themeData.slug,
label: themeData.title,
} );
// The current PDF theme selector should be set to the new theme.
const selectorPdfId = $select.closest( '.wpforms-pdf' ).data( 'block-id' );
const setValue = selectorPdfId === reflectorElement.pdfId ? themeData.slug : $select.val();
app.updateThemeSelectorChoices( choices, updatedChoices, setValue );
} );
},
/**
* Update theme selector choices.
*
* @since 1.0.0
*
* @param {Object} choicesObj ChoicesJS instance.
* @param {Array} choices Choices.
* @param {string|null} setTheme Set theme after update, optional.
*/
updateThemeSelectorChoices( choicesObj, choices, setTheme = null ) {
if ( ! choicesObj?.setChoices ) {
return;
}
setTheme = setTheme ?? choicesObj.getValue( true );
WPForms.Admin.Builder?.UndoRedo?.preventRecord( true );
// noinspection JSVoidFunctionReturnValueUsed
choicesObj
.clearStore()
.setChoices( choices, 'value', 'label', true )
.setChoiceByValue( setTheme );
WPForms.Admin.Builder?.UndoRedo?.preventRecord( 'continue' );
},
/**
* Update theme selector color swatch.
*
* @since 1.0.0
*
* @param {Object} themeData Theme data.
* @param {string} colorKey Color key.
* @param {string} color Color value.
*/
updateThemeSelectorColorSwatch( themeData, colorKey, color ) {
if ( ! colorKey ) {
return;
}
const keys = Object.keys( themeData.colors );
const index = keys.indexOf( colorKey );
// If the color key is not found, OR index is out of range, do nothing.
if ( index < 0 || index > 4 ) {
return;
}
const $choiceSwatches = $( `.choices__item[data-value="${ themeData.slug }"] .wpforms-theme-color-swatches` );
$choiceSwatches.each( function() {
const $swatches = $( this );
$swatches
.find( `.wpforms-theme-color-swatch[data-index="${ index }"]` )
.css( 'background-color', color );
} );
},
/**
* Delete theme.
*
* @since 1.0.0
*
* @param {jQuery} $select The select element.
*/
deleteTheme( $select ) {
const themeSlug = $select.val();
// Delete the theme from the runtime object.
delete wpformsPDF.customThemes[ themeSlug ];
// Delete the theme from the server.
app.updateEntityData( { slug: themeSlug, delete: true }, 'theme' );
const choices = $select?.data( 'choicesjs' );
if ( ! choices ) {
return;
}
const updatedChoices = choices._store.choices;
// Delete theme from the choices.
for ( const choice of updatedChoices ) {
if ( choice.value === themeSlug ) {
delete updatedChoices[ updatedChoices.indexOf( choice ) ];
}
}
// Update theme selectors in all PDFs.
$( '.wpforms-pdf-theme-selector select' ).each( function() {
const eachChoices = $( this ).data( 'choicesjs' );
app.updateThemeSelectorChoices( eachChoices, updatedChoices, wpformsPDF.defaultTheme );
} );
// Apply theme changes.
WPFormsPDFBuilder.appearance.applyThemeChanges( $select );
},
/**
* -------- Template processing functions. --------
*/
/**
* Process template change.
*
* @since 1.0.0
*
* @param {Object} templateData Theme data object.
* @param {Object} reflectorElement Reflector element data object.
*/
processTemplateAlternate( templateData, reflectorElement ) {
if ( ! templateData || ! reflectorElement ) {
return;
}
// When the template is not custom, we should first create the custom template.
if ( ! templateData.isCustom ) {
templateData = app.createNewTemplate( templateData, reflectorElement );
} else {
templateData = app.updateTemplateData( templateData.slug, reflectorElement );
}
app.updateEntityData( templateData, 'template' );
},
/**
* Create a new template.
*
* @since 1.0.0
*
* @param {Object} templateData Theme data object.
* @param {Object} reflectorElement Reflector element data object.
*
* @return {Object|null} New theme data.
*/
createNewTemplate( templateData, reflectorElement ) {
const templateSlug = templateData.slug ?? '';
if ( ! templateSlug ) {
return null;
}
const newSlug = app.getNewSlug( templateSlug, 'template' );
const copyNumber = app.getCopyNumber( templateSlug, 'template' );
const newTitle = app.getCopyTitle( copyNumber, templateData );
// Create new template data.
const newTemplateData = {
category: templateData.category ?? '',
title: newTitle,
appearance: { ...templateData.appearance },
text: { ...templateData.text },
isCustom: true,
slug: newSlug,
baseTemplate: templateSlug,
};
// Preserve email_style from the base template (e.g., 'compact' for table layout).
if ( templateData.email_style ) {
// eslint-disable-next-line camelcase
newTemplateData.email_style = templateData.email_style;
}
wpformsPDF.customTemplates[ newSlug ] = newTemplateData;
app.updateTemplateData( newSlug, reflectorElement );
app.addTemplateSelectorItem( newTemplateData, reflectorElement );
app.toggleCustomEntityVisibility( {}, $( `#wpforms-panel-field-pdfs-${ reflectorElement.pdfId }-template_style` ) );
return newTemplateData;
},
/**
* Update the template data.
*
* @since 1.0.0
*
* @param {string} templateSlug Theme slug.
* @param {Object} reflectorElement Reflector element data object.
* @param {string} newTitle New title, optional.
*
* @return {Object|null} Theme data.
*/
updateTemplateData( templateSlug, reflectorElement, newTitle = '' ) { // eslint-disable-line complexity
const templateData = app.getTemplateData( templateSlug );
// When the template is not custom, we should do nothing.
if ( ! templateData || ! templateData.isCustom ) {
return null;
}
templateData.text[ reflectorElement.setting ] = reflectorElement.value ?? '';
if ( newTitle ) {
templateData.title = newTitle;
}
wpformsPDF.customTemplates[ templateSlug ] = templateData;
return templateData;
},
/**
* Add a new template to the Template selector.
*
* @since 1.0.0
*
* @param {Object} templateData Template data.
* @param {Object} reflectorElement Reflector element data object.
*/
addTemplateSelectorItem( templateData, reflectorElement ) {
// language=HTML
const $option = $( '<option></option>' )
.attr( 'value', templateData.slug )
.text( templateData.title );
$( '.wpforms-pdf-template-style select' ).each( function() {
const $select = $( this );
const $categorySelect = $select
.closest( '.wpforms-panel-fields-group-inner' )
.find( '.wpforms-pdf-template-category select' );
if ( $categorySelect.val() !== templateData.category ) {
return;
}
$select.prepend( $option.clone() );
// The current PDF template selector should be set to the new template.
const selectorPdfId = $select.closest( '.wpforms-pdf' ).data( 'block-id' );
const setValue = selectorPdfId === reflectorElement.pdfId ? templateData.slug : $select.val();
$select.val( setValue );
} );
},
/**
* Delete theme.
*
* @since 1.0.0
*
* @param {jQuery} $select The select element.
*/
deleteTemplate( $select ) {
const templateSlug = $select.val();
const baseTemplate = app.getTemplateData( templateSlug )?.baseTemplate;
// Delete the template from the runtime object.
delete wpformsPDF.customTemplates[ templateSlug ];
// Delete the template from the server.
app.updateEntityData( { slug: templateSlug, delete: true }, 'template' );
// Update template selectors in all PDFs.
$( '.wpforms-pdf-template-style select' ).each( function() {
const $eachSelect = $( this );
const isCurrentTemplate = $eachSelect.val() === templateSlug;
$eachSelect.find( `option[value="${ templateSlug }"]` ).remove();
if ( ! isCurrentTemplate ) {
return;
}
$eachSelect.val( baseTemplate );
} );
$select.trigger( 'change' );
},
};
// Return the public-facing methods.
return app;
}