File: /home/globfdxw/www/wp-content/plugins/wpforms-pdf/assets/js/modules/preview-reflector.js
/* global WPFormsPDFBuilder, WPFormsUtils, wpf, wpformsPDF */
/**
* WPForms PDF: Preview Reflector 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
/**
* Implement the Reflector object.
*
* @since 1.0.0
*
* @type {Object}
*/
const reflector = {
/**
* Current element Id.
*
* @since 1.0.0
*
* @type {Object}
*/
currentId: null,
/**
* Data storage.
*
* @since 1.0.0
*
* @type {Object}
*/
data: {},
/**
* Initialize module.
*
* @since 1.0.0
*/
init() {
reflector.$builder = $( '#wpforms-builder' );
},
/**
* Add an element to the reflector data.
*
* @since 1.0.0
*
* @param {jQuery} $input The input element.
*
* @return {boolean} True on success.
*/
addElement( $input ) { // eslint-disable-line complexity
const id = reflector.getInputId( $input );
reflector.currentId = id;
if ( ! id ) {
return false;
}
// Skip if we have an element.
if ( reflector.data[ id ] ) {
return true;
}
// Otherwise, create the new current reflector data element.
/* eslint-disable no-multi-spaces */
const data = {
id, // Setting input id attribute.
$input, // Setting input element.
value: null, // Setting input value.
pdfId: null, // PDF block ID.
group: null, // PDF settings group.
setting: '', // Setting slug.
pair: null, // Pair data for the setting.
$previewContainer: null, // Element container inside the preview iframe.
themeColorKey: null, // Theme color key.
themeColorValue: null, // Theme color value.
themeSlug: null, // Theme slug.
templateValue: null, // Template value.
isInitialData: true, // Whether the data is initial.
};
/* eslint-enable no-multi-spaces */
// Get the input value.
data.value = reflector.getInputVal( $input );
// Regular expression to match the pdfId and a setting key.
const regex = /wpforms-panel-field-pdfs-(\d+)-([a-zA-Z_\d]+)/;
const match = id.match( regex );
// If we have a match with the expected groups.
if ( match && match.length === 3 ) {
data.pdfId = Number( match[ 1 ] );
data.settingOrginal = match[ 2 ];
data.setting = data.settingOrginal
.replace( 'notification_', '' )
.replace( 'general_', '' );
}
data.pair = reflector.getSettingPair( data.setting );
if ( ! data.pair ) {
return false;
}
// Get the corresponding preview iframe document.
const $previewDoc = $( WPFormsPDFBuilder.preview.getPreviewIframeDoc( data.pdfId ) );
data.$previewContainer = $previewDoc.find( data.pair?.outline ?? data.pair?.selector );
data.$updateContainer = data.pair?.outline ? $previewDoc.find( data.pair?.selector ) : data.$previewContainer;
data.group = $input.closest( '.wpforms-panel-fields-group' ).data( 'group' );
// Add the element to reflector data.
reflector.data[ id ] = data;
return true;
},
/**
* Update an element in the reflector data.
*
* @since 1.0.0
*
* @param {jQuery} $input The input element.
* @param {string} context The element context.
*/
updateElement( $input, context = '' ) {
const id = reflector.getInputId( $input );
reflector.currentId = id;
if ( ! id ) {
return;
}
// Attempt to add the element if it doesn't exist.
if ( ! reflector.data[ id ] && ! reflector.addElement( $input ) ) {
return;
}
// Get the current reflector data element.
let data = { ...reflector.data[ id ] };
data.context = context;
data.prevValue = data.value;
data.value = reflector.getInputVal( $input );
// Add theme color data to the element.
data = reflector.addThemeColorDataToElement( data );
data = reflector.normalizeElementData( data );
// Do not proceed if the value hasn't changed.
if ( data.value === reflector.data[ id ].value && ! data.isInitialData ) {
return;
}
// After updating data, set isInitialData to false.
data.isInitialData = false;
// Update the reflector data storage.
reflector.data[ id ] = { ...data };
WPFormsUtils.triggerEvent( reflector.$builder, 'wpformsPDFReflectorElementUpdate', [ data ] );
reflector.updateContainer( data );
},
/**
* Clear reflector data for the given PDF.
*
* @since 1.0.0
*
* @param {string} pdfId PDF block ID.
*/
clearData( pdfId ) {
Object.entries( reflector.data ).forEach( ( [ key, value ] ) => {
if ( value?.pdfId === Number( pdfId ) ) {
delete reflector.data[ key ];
}
} );
},
/**
* Get input ID.
*
* @since 1.0.0
*
* @param {jQuery} $input Input element.
*
* @return {string|null} Input ID.
*/
getInputId( $input ) {
const id = $input.attr( 'id' );
if ( id ) {
return id;
}
if ( $input.hasClass( 'choicesjs' ) ) {
return $input.find( 'select.choices__input' ).attr( 'id' );
}
if ( $input.hasClass( 'wpforms-smart-tags-widget' ) ) {
return $input.closest( '.wpforms-panel-field' )
.find( '.wpforms-smart-tags-widget-original' )
.attr( 'id' );
}
return null;
},
/**
* Get the value from the input element.
*
* @since 1.0.0
*
* @param {jQuery} $input Input element.
*
* @return {any} The input value.
*/
getInputVal( $input ) {
const inputType = $input.attr( 'type' );
if ( inputType === 'checkbox' ) {
return $input.is( ':checked' );
}
return $input.val();
},
/**
* Get the value of a setting.
*
* @since 1.0.0
*
* @param {string} pdfId The ID of the PDF settings section.
* @param {string} setting The setting slug.
*
* @return {string|null} The setting value.
*/
getSettingValue( pdfId, setting ) {
if ( ! pdfId || ! setting ) {
return null;
}
const $regularField = $( `#wpforms-panel-field-pdfs-${ pdfId }-${ setting }` );
if ( $regularField.length ) {
return $regularField.val();
}
const templateCategory = $( `wpforms-panel-field-pdfs-${ pdfId }-template_category` ).val();
const prefix = templateCategory === 'notification' ? 'notification' : 'general';
const $input = $( `#wpforms-panel-field-pdfs-${ pdfId }-${ prefix }_${ setting }` );
return $input.val();
},
/**
* Add theme color data to the element.
*
* @since 1.0.0
*
* @param {Object} element Element data object.
*
* @return {Object} Element data object.
*/
addThemeColorDataToElement( element ) { // eslint-disable-line complexity
const templateSlug = $( `#wpforms-panel-field-pdfs-${ element.pdfId }-template_style` ).val();
const templateData = WPFormsPDFBuilder.templates.getTemplateData( templateSlug );
if ( ! templateData ) {
return element;
}
const templateValue = templateData.appearance?.[ element.setting ] || templateData.text?.[ element.setting ];
const templateColorKey = /^\{color_\w+}$/.test( templateValue )
? templateValue.replace( '{color_', '' ).replace( '}', '' )
: null;
const themeEditorColorKey = /^theme_color_\w+$/.test( element.setting )
? element.setting.replace( 'theme_color_', '' )
: null;
const themeColorKey = templateColorKey || themeEditorColorKey;
const themeSlug = $( `#wpforms-panel-field-pdfs-${ element.pdfId }-theme` ).val();
const themeData = WPFormsPDFBuilder.appearance.getThemeData( themeSlug );
const isThemeColorChange = Boolean( themeEditorColorKey );
const themeColorValue = isThemeColorChange ? element.value : ( themeData?.colors[ themeColorKey ] ?? null );
return {
...element,
...{ themeSlug, themeColorKey, themeColorValue, templateValue, templateSlug, isThemeColorChange },
};
},
/**
* Normalize element data.
*
* @since 1.0.0
*
* @param {Object} element Element data object.
*
* @return {Object} Element data object.
*/
normalizeElementData( element ) {
// Empty and invalid colors are transparent.
if ( element.setting?.includes( '_color' ) ) {
element.value = WPFormsUtils.cssColorsUtils.isValidColor( element.value ) ? element.value : '#ffffff00';
}
// Templates contain images that should be turned into full URLs.
if ( element.setting === 'logo_url' ) {
element.value = WPFormsPDFBuilder.appearance.getLogoUrl( element.value, element.themeSlug, element.templateSlug );
}
// Apply actual font name to the element.
if ( element.setting === 'font' ) {
element.previewValue = wpformsPDF.fonts[ element.value ];
}
return element;
},
/**
* Get the element data.
*
* @since 1.0.0
*
* @param {string} id The element ID.
*
* @return {Object} Element data object.
*/
getElement( id = '' ) {
return reflector.data[ id ] ?? reflector.data[ reflector.currentId ];
},
/**
* Initialize pair definitions.
*
* @since 1.0.0
*/
initPairDefinitions() { // eslint-disable-line max-lines-per-function
if ( reflector.pairDefinitions ) {
return;
}
// Define setting-preview pairs.
/* eslint-disable camelcase */
reflector.pairDefinitions = {
theme_color: {
selector: '.page-background',
},
logo_url: {
selector: 'img.logo',
action: 'setAttribute',
attr: 'src',
},
logo_size: {
selector: '.logo-container',
outline: 'img.logo',
action: 'setAttribute',
attr: 'data-size',
},
logo_position: {
selector: '.header, .logo-container',
outline: '.logo-container',
action: 'setAttribute',
attr: 'data-align',
},
font: {
selector: '.container-content *, .container-background *',
outline: '.container-background-fill',
property: 'font-family',
},
font_size: {
selector: '.container-content *, .container-background *',
outline: '.container-background-fill',
property: 'font-size',
},
text_color: {
selector: '.container-content .content *',
outline: '.container-background-fill',
property: 'color',
},
content_color: {
selector: '.container-content .content, .container-content .content *',
outline: '.content',
property: 'color',
},
link_color: {
selector: '.container-content .content a',
property: 'color',
},
page_background_color: {
selector: '.page-background',
property: 'background',
conditional: {
condition: '!=',
setting: 'page_background_image',
value: 'none',
action: 'refreshPreview',
},
},
page_background_color_end: {
selector: '.page-background',
conditional: {
condition: '!=',
setting: 'page_background_image',
value: 'none',
action: 'refreshPreview',
},
},
page_background_image: {
selector: '.page-background',
action: 'refreshPreviewBackground',
},
container_background_color: {
selector: '.container-background-fill',
outline: '.container-background-fill',
property: 'background-color',
},
container_shadow: {
selector: '.container-shadow',
outline: '.container-background-fill',
action: 'setAttribute',
attr: 'data-shadow',
},
container_border_style: {
selector: '.container-background-fill',
property: 'border-style',
},
container_border_size: {
selector: '.container-background-fill',
property: 'border-width',
},
container_border_color: {
selector: '.container-background-fill',
property: 'border-color',
},
container_border_radius: {
selector: '.container-background-fill',
property: 'border-radius',
},
signature_size: {
selector: '.signature_image',
outline: '.signature',
action: 'setAttribute',
attr: 'data-size',
},
signature_position: {
selector: '.signature_image',
outline: '.signature',
action: 'setAttribute',
attr: 'data-align',
},
signature_url: {
selector: '.signature_image',
action: 'setAttribute',
attr: 'src',
},
signature_type: {
selector: '.signature',
action: 'setAttribute',
attr: 'data-type',
},
signature_show: {
selector: '.signature',
action: 'toggleClassInverse',
class: 'hidden',
},
badge_show: {
selector: '.badge',
action: 'toggleClassInverse',
class: 'hidden',
},
orientation: {
selector: '.page-background',
action: 'changePageOrientation',
},
};
/* eslint-enable camelcase */
},
/**
* Get the preview pair data for a given setting.
*
* @since 1.0.0
*
* @param {string} setting Setting slug.
*
* @return {Object} Pair data object.
*/
getSettingPair( setting ) {
if ( ! setting ) {
return null;
}
const data = reflector.pairDefinitions[ setting ];
if ( data ) {
return data;
}
// Theme color settings.
if ( setting.includes( 'theme_color_' ) ) {
return reflector.pairDefinitions.theme_color;
}
// Text color settings.
if ( setting.includes( '_color' ) ) {
const selector = setting.replace( '_color', '' );
return {
selector: `.${ selector }, .${ selector } *`,
outline: `.${ selector }`,
property: 'color',
};
}
// Replace text is a default action for all other settings.
return {
selector: '.' + setting,
action: 'replaceText',
};
},
/**
* Highlight container.
*
* @since 1.0.0
*
* @param {jQuery} $container Container jQuery object.
*/
highLightContainer( $container ) {
reflector.removeHighLighting();
$container.addClass( 'preview-highlight' );
},
/**
* Remove highlightings.
*
* @since 1.0.0
*/
removeHighLighting() {
const doc = WPFormsPDFBuilder.preview.getPreviewIframeDoc();
$( doc ).find( '.preview-highlight' ).removeClass( 'preview-highlight' );
},
/**
* Update container.
*
* @since 1.0.0
*
* @param {Object} data Reflector element data.
*/
updateContainer( data ) {
if ( ! data || ! data.$updateContainer?.length ) {
return;
}
const action = data.pair.action ?? 'injectStyle';
const actionCallback = reflectorActions[ action ]; // eslint-disable-line no-use-before-define
if ( typeof actionCallback === 'function' ) {
actionCallback( data );
}
// Run conditional action.
reflector.conditionalAction( data );
},
/**
* Run conditional action.
*
* @since 1.0.0
*
* @param {Object} data Pair data.
*/
conditionalAction( data ) { // eslint-disable-line complexity
if ( ! data.pair?.conditional ) {
return;
}
const cond = data.pair.conditional;
if ( ! cond.setting || ! cond.action || ! cond.condition ) {
return;
}
const settingValue = reflector.getSettingValue( data.pdfId, cond.setting );
// Define process condition logic.
const process = {
e: () => {
return ! Boolean( settingValue );
},
'!e': () => {
return Boolean( settingValue );
},
'==': () => {
return settingValue === cond.value;
},
'!=': () => {
return settingValue !== cond.value;
},
'>': () => {
return settingValue > cond.value;
},
'>=': () => {
return settingValue >= cond.value;
},
'<': () => {
return settingValue < cond.value;
},
'<=': () => {
return settingValue <= cond.value;
},
};
if ( ! process[ cond.condition ] || ! process[ cond.condition ]() ) {
return;
}
const actionCallback = reflectorActions[ cond.action ]; // eslint-disable-line no-use-before-define
if ( typeof actionCallback !== 'function' ) {
return;
}
actionCallback( data );
},
};
/**
* The Reflector actions object.
*
* @since 1.0.0
*
* @type {Object}
*/
const reflectorActions = {
/**
* Injects a new style or updates an existing style.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
injectStyle( data ) { // eslint-disable-line complexity
if ( ! data || ! data.$updateContainer?.length ) {
return;
}
const $body = data.$updateContainer.closest( 'body' );
const previewValue = data.previewValue ?? data.value;
// Set --wpforms-theme-color-{ data.themeColorKey } CSS variable.
if ( data.themeColorKey ) {
$body.css( `--wpforms-theme-color-${ data.themeColorKey }`, data.themeColorValue );
}
// Set --wpforms-appearance-{ data.setting } CSS variable.
if ( data.group === 'settings_pdf_appearance' ) {
$body.css( `--wpforms-appearance-${ data.setting }`, previewValue );
}
// Set --wpforms-text-color-{ data.setting } CSS variable.
if ( data.group === 'settings_pdf_template' && data.setting.includes( '_color' ) ) {
$body.css( `--wpforms-text-color-${ data.setting }`, data.value );
}
},
/**
* Replace text.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
replaceText( data ) {
data.$updateContainer.html( wpf.sanitizeHTML( data.value ) );
},
/**
* Toggle CSS class (inverse logic).
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
toggleClassInverse( data ) {
data.$updateContainer.toggleClass( data.pair.class, ! data.value );
},
/**
* Set attribute.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
setAttribute( data ) {
data.$updateContainer.attr( data.pair.attr, data.value );
},
/**
* Refresh the preview.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
refreshPreview( data ) {
if ( ! data.pdfId ) {
return;
}
WPFormsPDFBuilder.preview.fetchPreview( data.pdfId );
},
/**
* Refresh the preview on change of the background image.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
refreshPreviewBackground( data ) {
if ( ! data.pdfId ) {
return;
}
if ( data.value === 'none' && data.prevValue === 'none' ) {
return;
}
WPFormsPDFBuilder.preview.fetchPreview( data.pdfId );
},
/**
* Change page orientation.
*
* @since 1.0.0
*
* @param {Object} data Pair data object.
*/
changePageOrientation( data ) {
if ( ! data.pdfId ) {
return;
}
reflector.$preview = reflector.$preview ?? $( '#wpforms-pdf-preview' );
reflector.$preview.attr( 'data-orientation', data.value );
WPFormsPDFBuilder.preview.fetchPreview( data.pdfId );
},
};
// Return the public-facing methods.
return reflector;
}