';
@@ -807,8 +807,18 @@ function render_all_input_types( $name, $data, $fields_type, $field_index, $valu
$html_input .= '
';
foreach ( $condition_rules as $rule_index => $condition ) {
- $element_values = isset( $condition['element_values'] ) ? stripslashes( $condition['element_values'] ) : '';
- $element = isset( $condition['elements'] ) ? stripslashes( $condition['elements'] ) : '';
+ $element_values = isset( $condition['element_values'] ) ? stripslashes( $condition['element_values'] ) : '';
+ $element = isset( $condition['elements'] ) ? stripslashes( $condition['elements'] ) : '';
+ $element_constant_value = isset( $condition['element_constant'] ) ? stripslashes( $condition['element_constant'] ) : '';
+
+ $element_between_value_to = '';
+ $element_between_value_from = '';
+
+ if ( isset( $condition['cond-between-interval'] ) && is_array( $condition['cond-between-interval'] ) ) {
+ $element_between_value_to = isset( $condition['cond-between-interval']['to'] ) ? $condition['cond-between-interval']['to'] : '';
+ $element_between_value_from = isset( $condition['cond-between-interval']['from'] ) ? $condition['cond-between-interval']['from'] : '';
+ }
+
$operator_is = ( $condition['operators'] == 'is' ) ? 'selected="selected"' : '';
$operator_not = ( $condition['operators'] == 'not' ) ? 'selected="selected"' : '';
$operator_greater = ( $condition['operators'] == 'greater than' ) ? 'selected="selected"' : '';
@@ -826,22 +836,53 @@ function render_all_input_types( $name, $data, $fields_type, $field_index, $valu
$html_input .= '
';
+ $pro_enabled = ppom_pro_is_installed() && 'valid' === apply_filters( 'product_ppom_license_status', '' );
+
+ $html_input .= '
';
$html_input .= ' ';
$html_input .= '
';
// conditional elements values
- $html_input .= '
';
+ $html_input .= '
';
@@ -891,12 +932,33 @@ function render_all_input_types( $name, $data, $fields_type, $field_index, $valu
$html_input .= '
';
// is
+ $pro_enabled = ppom_pro_is_installed() && 'valid' === apply_filters( 'product_ppom_license_status', '' );
+
$html_input .= '
';
$html_input .= ' ';
$html_input .= '
';
diff --git a/css/ppom-admin.css b/css/ppom-admin.css
index f31af64..899cfa3 100644
--- a/css/ppom-admin.css
+++ b/css/ppom-admin.css
@@ -144,6 +144,7 @@ ul.ppom-options-container li {
.ppom-condition-style-wrap p {
font-size: 15px;
+ margin: 0px;
}
/*.ppom-slider select.form-control {*/
@@ -769,6 +770,11 @@ select {
display: block;
}
+.row.ppom-condition-style-wrap {
+ display: flex;
+ align-items: center;
+}
+
@media (min-width: 992px) {
.col-md-6 {
width: 50% !important;
@@ -1796,4 +1802,30 @@ header.ppom-modal-header {
.ppom-attach-container .ppom-settings-container {
margin: 10px 0;
-}
\ No newline at end of file
+}
+.ppom-hide-element {
+ display: none !important;
+}
+
+.ppom-invisible-element {
+ visibility: hidden;
+}
+
+.ppom-between-input-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+
+ gap: 10px;
+}
+
+.ppom-between-input-container span {
+ font-size: 16px;
+}
+
+.ppom-upsell-condition {
+ font-size: 16px;
+ padding: 9px;
+ display: flex;
+ align-items: center;
+}
diff --git a/inc/functions.php b/inc/functions.php
index b65ec18..5faa79f 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -2349,10 +2349,30 @@ function ppom_get_conditional_data_attributes( $meta ) {
$bound = isset( $conditions['bound'] ) ? ppom_wpml_translate( $conditions['bound'], 'PPOM' ) : '';
$visibility = isset( $conditions['visibility'] ) ? ppom_wpml_translate( $conditions['visibility'], 'PPOM' ) : '';
-
+
$conditions['rules'] = array_filter(
$conditions['rules'],
function( $rule ) {
+ if ( in_array( $rule['operators'], array( 'any', 'empty', 'even-number', 'odd-number', 'regex') ) ) {
+ return true;
+ }
+
+ if ( in_array( $rule['operators'], array( 'number-multiplier', 'regex', 'contains', 'not-contains') ) ) {
+ return ! empty( $rule['element_constant'] );
+ }
+
+ if ( in_array( $rule['operators'], array( 'greater than', 'less than', 'is', 'not' ) ) ) {
+ return ! empty( $rule['element_constant'] ) || ! empty( $rule['element_values'] );
+ }
+
+ if ( 'between' === $rule['operators'] ) {
+ return (
+ ! empty( $rule['cond-between-interval']) && is_array( $rule['cond-between-interval'] )
+ && isset( $rule['cond-between-interval']['to'] )
+ && isset( $rule['cond-between-interval']['from'] )
+ );
+ }
+
return ! empty( $rule['element_values'] );
}
);
@@ -2362,19 +2382,32 @@ function( $rule ) {
$attr_html .= ' data-cond-bind="' . esc_attr( $bound ) . '"';
$attr_html .= ' data-cond-visibility="' . esc_attr( strtolower( $visibility ) ) . '"';
- $index = 0;
+ $index = 0;
+ $pro_enabled = ppom_pro_is_installed() && 'valid' === apply_filters( 'product_ppom_license_status', '' );
+
foreach ( $conditions['rules'] as $rule ) {
- $counter = ++ $index;
- $input = 'input' . $counter;
- $value = 'val' . $counter;
- $opr = 'operator' . $counter;
- $element = isset( $rule['elements'] ) ? ppom_wpml_translate( $rule['elements'], 'PPOM' ) : '';
- $element_val = isset( $rule['element_values'] ) ? ppom_wpml_translate( $rule['element_values'], 'PPOM' ) : '';
- $operator = isset( $rule['operators'] ) ? ppom_wpml_translate( $rule['operators'], 'PPOM' ) : '';
- $attr_html .= ' data-cond-' . $input . '="' . esc_attr( $element ) . '"';
- $attr_html .= ' data-cond-' . $value . '="' . esc_attr( $element_val ) . '"';
- $attr_html .= ' data-cond-' . $opr . '="' . esc_attr( $operator ) . '"';
+ $counter = ++ $index;
+ $input = 'input' . $counter;
+ $value = 'val' . $counter;
+ $opr = 'operator' . $counter;
+ $element = isset( $rule['elements'] ) ? ppom_wpml_translate( $rule['elements'], 'PPOM' ) : '';
+ $element_val = isset( $rule['element_values'] ) ? ppom_wpml_translate( $rule['element_values'], 'PPOM' ) : '';
+ $constant_val = isset( $rule['element_constant'] ) ? ppom_wpml_translate( $rule['element_constant'], 'PPOM' ) : '';
+ $operator = isset( $rule['operators'] ) ? ppom_wpml_translate( $rule['operators'], 'PPOM' ) : '';
+
+ $attr_html .= ' data-cond-' . $input . '="' . esc_attr( $element ) . '"';
+ $attr_html .= ' data-cond-' . $value . '="' . esc_attr( $element_val ) . '"';
+ $attr_html .= ' data-cond-' . $opr . '="' . esc_attr( $operator ) . '"';
+
+ if ( $pro_enabled && ! empty( $constant_val ) ) {
+ $attr_html .= ' data-cond-constant-val-' . $counter . '="' . esc_attr( $constant_val ) . '"';
+ }
+
+ if ( $pro_enabled && 'between' === $operator && isset( $rule['cond-between-interval'] ) ) {
+ $attr_html .= ' data-cond-between-from-' . $counter . '="' . esc_attr( $rule['cond-between-interval']['from'] ) . '"';
+ $attr_html .= ' data-cond-between-to-' . $counter . '="' . esc_attr( $rule['cond-between-interval']['to'] ) . '"';
+ }
}
}
diff --git a/js/admin/ppom-admin.js b/js/admin/ppom-admin.js
index f4bec3a..300a3ba 100644
--- a/js/admin/ppom-admin.js
+++ b/js/admin/ppom-admin.js
@@ -1,4 +1,39 @@
+// @ts-check
"use strict";
+
+const FIELD_COMPATIBLE_WITH_SELECT_OPTIONS = [ 'select', 'radio', 'checkbox', 'switcher' ];
+const OPERATOR_COMPARISON_VALUE_FIELD_TYPE = {
+ 'select': FIELD_COMPATIBLE_WITH_SELECT_OPTIONS,
+}
+const COMPARISON_VALUE_CAN_USE_SELECT = [ 'is', 'not', 'greater than', 'less than' ];
+const HIDE_COMPARISON_INPUT_FIELD = ['any', 'empty', 'odd-number', 'even-number'];
+const FIELDS_COMPATIBLE_WITH_TEXT = [ 'text', 'textarea', 'date', 'email' ]
+const FIELDS_COMPATIBLE_WITH_NUMBERS = [ ...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, 'number' ];
+const OPERATORS_FIELD_COMPATIBILITY = {
+ 'is': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT, ...FIELDS_COMPATIBLE_WITH_NUMBERS],
+ 'not': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT, ...FIELDS_COMPATIBLE_WITH_NUMBERS],
+ 'greater than': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'less than': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'even-number': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'odd-number': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'between': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'number-multiplier': FIELDS_COMPATIBLE_WITH_NUMBERS,
+ 'any': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT, ...FIELDS_COMPATIBLE_WITH_NUMBERS],
+ 'empty': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT, ...FIELDS_COMPATIBLE_WITH_NUMBERS],
+ 'contains': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT],
+ 'not-contains': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT],
+ 'regex': [...FIELD_COMPATIBLE_WITH_SELECT_OPTIONS, ...FIELDS_COMPATIBLE_WITH_TEXT]
+}
+
+const proOperatorOptionsToLock = new Set();
+
+/**
+ * An array to store available condition targets.
+ *
+ * @type {Array<{fieldLabel?: string, fieldId?: string, fieldType?: string, canUse: boolean}>}
+ */
+const availableConditionTargets = [];
+
jQuery(function($) {
var loader = new ImageLoader(ppom_vars.loader);
@@ -433,6 +468,9 @@ jQuery(function($) {
} );
clone_new_field.find('.ppom-field-checker').attr('data-field-index', field_no);
clone_new_field.find('.ppom-field-checker').addClass('ppom-add-fields-js-action');
+
+ // NOTE: Hide Condition tab on new field modal because of wrong behavior.
+ clone_new_field.find('#condition_tab').addClass('ppom-hide-element');
// var color_picker_input = clone_new_field.find('.ppom-color-picker-init').clone();
// clone_new_field.find('.ppom-color-picker-cloner').html(color_picker_input);
@@ -1187,56 +1225,212 @@ jQuery(function($) {
});
}
+ /**
+ * Filter the operator options list based on the target type field.
+ *
+ * @param {string?} fieldType The PPOM field type.
+ * @param {HTMLSelectElement} operatorSelectField The select input for condition operator.
+ * @returns
+ */
+ function toggleOperatorFieldByTargetType( fieldType, operatorSelectField ) {
+ if ( ! operatorSelectField ) {
+ return;
+ }
+
+ let shouldHideSelectInput = true;
+ const currentValue = operatorSelectField?.value;
+
+ operatorSelectField.querySelectorAll('optgroup').forEach( optgroup => {
+ let shouldHideGroup = true;
+ optgroup.querySelectorAll('option').forEach( option => {
+ const isAvailable = option?.value && OPERATORS_FIELD_COMPATIBILITY[option.value] ? OPERATORS_FIELD_COMPATIBILITY[option.value].includes(fieldType) : option?.value;
+ if ( shouldHideGroup && isAvailable ) {
+ shouldHideGroup = false;
+ }
+
+ if ( option.value === currentValue && !isAvailable ) {
+ operatorSelectField.value = 'any'; // NOTE: Default to 'any' if the current select value is unavailable.
+ }
+
+ option.classList.toggle('ppom-hide-element', !isAvailable );
+ });
+
+ if ( ! shouldHideGroup ) {
+ shouldHideSelectInput = false;
+ }
+
+ optgroup.classList.toggle( 'ppom-hide-element', shouldHideGroup );
+ });
+
+ operatorSelectField.classList.toggle( 'ppom-invisible-element', shouldHideSelectInput );
+ tryToggleConditionInputFields( operatorSelectField );
+ }
/**
- 27- Get All Fields Title On Condition Element Value After Click On Condition Tab
+ 27- Refresh the condition comparison option list for PPOM field target that are of type select.
**/
- // populate_conditional_elements();
+ function updateTargetComparisonValueSelect( targetSelect, conditionContainer, initialSelectedValue ) {
+ /** @type {string?} */
+ const targetElementNameToPullOptions = targetSelect.value;
- $(document).on('change', 'select[data-metatype="elements"]', function(e) {
- e.preventDefault();
-
- var element_name = $(this).val();
- var div = $(this).closest('.ppom-slider');
+ /** @type {HTMLDivElement?} */
+ conditionContainer ??= targetSelect.closest('.webcontact-rules');
+ const targetSelectOptions = conditionContainer?.querySelector('select[data-metatype="element_values"]');
- var selected_rule_box = $(this).closest('.webcontact-rules');
- var element_value_box = selected_rule_box.find('select[data-metatype="element_values"]');
+ if ( !conditionContainer || !targetSelectOptions ) {
+ return;
+ }
- $(".ppom-slider").each(function(i, item) {
+ document.querySelectorAll('.ppom-slider').forEach(sliderItem => {
- var data_name = $(item).find('input[data-metatype="data_name"]').val();
+ const targetElementFieldId = sliderItem.querySelector('input[data-metatype="data_name"]')?.value;
+ if ( targetElementFieldId !== targetElementNameToPullOptions ) {
+ return;
+ }
- if (data_name == element_name) {
+ const operatorsInput = conditionContainer.querySelector('[data-metatype="operators"]');
+ if ( ! operatorsInput ) {
+ return;
+ }
+
+ // Reset the options lists based on the new selection.
+ const newOptions = [];
+
+ sliderItem.querySelectorAll('.data-options').forEach(/** @type {HTMLDivElement} */conditionValueContainer => {
+ const condition_type = conditionValueContainer.getAttribute('data-condition-type');
+
+ const conditionValueId = conditionValueContainer
+ .querySelector(
+ condition_type === 'simple_options'
+ ? 'input[data-metatype="option"]'
+ : '.ppom-image-option-title'
+ )?.value?.trim();
+
+ if ( ! conditionValueId ) {
+ return;
+ }
- // resetting
- jQuery(element_value_box).html('');
+ const optionElement = document.createElement('option');
+ optionElement.value = ppom_escape_html(conditionValueId);
+ optionElement.textContent = conditionValueId;
+
+ newOptions.push( optionElement );
+ });
+ targetSelectOptions.replaceChildren(...newOptions);
+ });
- $(item).find('.data-options').each(function(i, condition_val) {
+ if ( initialSelectedValue ) {
+ targetSelectOptions.value = initialSelectedValue;
+ }
+ }
+ /**
+ * Toggle the visibility for input fields type based on operator current value.
+ *
+ * @param {HTMLSelectElement?} conditionOperatorInput
+ * @returns
+ */
+ function tryToggleConditionInputFields( conditionOperatorInput ) {
+ if ( ! conditionOperatorInput ) {
+ return;
+ }
- var condition_type = $(condition_val).attr('data-condition-type');
- if (condition_type == 'simple_options') {
- var con_val = $(condition_val).find('input[data-metatype="option"]').val();
- }
- else if (condition_type == 'image_options') {
- var con_val = $(condition_val).find('.ppom-image-option-title').val();
- }
+ const selectedOperator = conditionOperatorInput?.value;
- if ($.trim(con_val) !== '') {
+ /**
+ * @type {HTMLDivElement|null}
+ */
+ const container = conditionOperatorInput?.closest('.webcontact-rules');
+ if ( !container) {
+ return;
+ }
+ /**
+ * @type {HTMLSelectElement|null}
+ */
+ const conditionTargetSelectOptionsInput = container.querySelector( 'select[data-metatype="element_values"]' );
- var val_id = $.trim(con_val);
+ /**
+ * @type {HTMLInputElement|null}
+ */
+ const conditionConstantInput = container.querySelector( '[data-metatype="element_constant"]' );
- var $html = '';
- $html += '
';
+ /**
+ * @type {HTMLSelectElement|null}
+ */
+ const conditionTargetSelectInput = container.querySelector( '[data-metatype="elements"]' );
- $($html).appendTo(element_value_box);
- }
- });
+ if ( !conditionConstantInput || !conditionTargetSelectOptionsInput || !conditionTargetSelectInput ) {
+ return;
+ }
+
+ /**
+ * @type {HTMLDivElement|null}
+ */
+ const betweenInputs = container.querySelector('.ppom-between-input-container');
+
+ let shouldHideSelectInput = false;
+ let shouldHideTextInput = false;
+ let shouldHideBetweenInputs = false;
+ let shouldHideUpsell = true;
+
+ if ( proOperatorOptionsToLock.has( selectedOperator ) ) {
+ shouldHideSelectInput = true;
+ shouldHideTextInput = true;
+ shouldHideBetweenInputs = true;
+ shouldHideUpsell = false;
+ }
+ else if ( 'between' === selectedOperator ) {
+ shouldHideSelectInput = true;
+ shouldHideTextInput = true;
+ shouldHideBetweenInputs = false;
+ }
+ else if ( HIDE_COMPARISON_INPUT_FIELD.includes( selectedOperator ) ) {
+ shouldHideSelectInput = true;
+ shouldHideTextInput = true;
+ shouldHideBetweenInputs = true;
+ } else {
+ shouldHideSelectInput = true;
+ shouldHideBetweenInputs = true;
+
+ /**
+ * @type {HTMLOptionElement|null}
+ */
+ const targetFieldTypeInput = conditionTargetSelectInput.querySelector(`option[value="${conditionTargetSelectInput.value}"]`);
+ if (
+ COMPARISON_VALUE_CAN_USE_SELECT.includes( selectedOperator ) &&
+ targetFieldTypeInput?.dataset?.fieldtype &&
+ OPERATOR_COMPARISON_VALUE_FIELD_TYPE['select'].includes( targetFieldTypeInput.dataset.fieldtype )
+ ) {
+ shouldHideTextInput = true;
+ shouldHideSelectInput = false;
}
- });
+ }
+
+ if ( shouldHideSelectInput && shouldHideTextInput && shouldHideBetweenInputs && shouldHideUpsell ) {
+ conditionConstantInput.parentNode?.classList.add('ppom-invisible-element'); // NOTE: Make the entire container visible to preserve the space.
+ } else {
+ conditionTargetSelectOptionsInput.classList.toggle("ppom-hide-element", shouldHideSelectInput );
+ conditionConstantInput.classList.toggle("ppom-hide-element", shouldHideTextInput );
+ betweenInputs?.classList.toggle("ppom-hide-element", shouldHideBetweenInputs );
+ container.querySelector('.ppom-upsell-condition')?.classList.toggle("ppom-hide-element", shouldHideUpsell);
+
+ conditionConstantInput.parentNode?.classList.remove('ppom-invisible-element');
+ }
+ }
+
+ // Apply actions on initialization based on operator value.
+ document.querySelectorAll('select[data-metatype="operators"]').forEach( conditionOperatorInput => {
+ tryToggleConditionInputFields( conditionOperatorInput );
+ });
+
+ // Apply actions when operator value changes.
+ document.addEventListener('change', function (e) {
+ if ( ! e.target.matches('select[data-metatype="operators"]') ) {
+ return;
+ }
+
+ e.preventDefault();
+ tryToggleConditionInputFields( e.target );
});
$(document).on('change', '[data-meta-id="conditions"] select[data-metatype="element_values"]', function(e) {
@@ -1248,79 +1442,164 @@ jQuery(function($) {
$(document).on('click', '.ppom-condition-tab-js', function(e) {
e.preventDefault();
+ populate_conditional_elements();
+ });
- var div = $(this).closest('.ppom-slider');
- var elements = div.find('select[data-metatype="elements"]');
+ /**
+ * Populate the condition target select with eligible options based on the operator.
+ *
+ * @param {HTMLSelectElement?} selectInput
+ * @param {string?} conditionOperator
+ * @param {string[]} excludeIds
+ * @returns
+ */
+ function populate_condition_target( selectInput, conditionOperator, excludeIds = [] ) {
+ if ( !selectInput ) {
+ return;
+ }
- elements.each(function(i, item) {
+ const newOptions = availableConditionTargets
+ .filter( ({ fieldId, canUse }) => canUse && !excludeIds.includes( fieldId) )
+ .map( target => {
+
+ const option = document.createElement('option');
+ option.value = target.fieldId;
+ option.textContent = target.fieldLabel;
+ option.dataset.fieldtype = target.fieldType;
+
+ return option;
+ });
- var conditional_elements = item.value;
- var exiting_meta = $(item).attr('data-existingvalue', conditional_elements);
- });
+ selectInput.replaceChildren( ...newOptions );
+ }
- populate_conditional_elements(elements);
+ function findFieldTypeById( fieldId ) {
+ if ( !fieldId ) {
+ return undefined;
+ }
- });
+ for ( const target of availableConditionTargets ) {
+ if ( target.fieldId === fieldId ) {
+ return target.fieldType;
+ }
+ }
- function populate_conditional_elements(elements) {
+ return undefined;
+ }
- // resetting
- jQuery('select[data-metatype="elements"]').html('');
+ function can_use_field_type( fieldType ) {
+ if ( ! fieldType?.length ) {
+ return false;
+ }
- jQuery(".ppom-slider").each(function(i, item) {
+ for ( const operatorCompatibleFields of Object.values( OPERATORS_FIELD_COMPATIBILITY ) ) {
+ if ( operatorCompatibleFields.includes( fieldType ) ) {
+ return true;
+ }
+ }
- var conditional_elements = jQuery(item).find(
- 'input[data-metatype="title"]').val();
- var conditional_elements_value = jQuery(item).find(
- 'input[data-metatype="data_name"]').val();
+ return false;
+ }
- if ($.trim(conditional_elements_value) !== '') {
+ /**
+ * Populate the condition target select with eligible options based on the operator on initialization and value change.
+ *
+ */
+ function populate_conditional_elements() {
- var $html = '';
- $html += '
';
+ // Get all available PPOM fields.
+ availableConditionTargets.splice(0, availableConditionTargets.length);
+ document.querySelectorAll(".ppom-slider").forEach(item => {
+ const fieldLabel = item.querySelector('input[data-metatype="title"]')?.value;
+ const fieldId = item.querySelector('input[data-metatype="data_name"]')?.value?.trim();
+ const fieldType = item.querySelector('input[data-metatype="type"]')?.value;
+ const canUse = can_use_field_type( fieldType );
- $($html).appendTo('select[data-metatype="elements"]');
+ if ( !fieldLabel || !fieldId || !fieldType ) {
+ return;
}
+ availableConditionTargets.push({ fieldLabel, fieldId, fieldType, canUse });
});
+
+ // Change the target options for all the rules.
+ document.querySelectorAll(".ppom-slider").forEach(item => {
+ if ( ! item.id ) {
+ return;
+ }
+ const conditionContainers = item.querySelector('div[data-meta-id="conditions"]')?.querySelectorAll('.webcontact-rules');
+
+ conditionContainers?.forEach(conditionContainer => {
+ const conditionTargetsSelect = conditionContainer.querySelector('[data-metatype="elements"]');
+ if ( ! conditionTargetsSelect ) {
+ return;
+ }
- // setting the existing conditional elements
- $(".ppom-slider").each(function(i, item) {
-
- $(item).find('select[data-metatype="elements"]').each(function(i, condition_element) {
+ const conditionOperatorSelect = conditionContainer.querySelector('[data-metatype="operators"]');
+ const fieldId = item.querySelector('input[data-metatype="data_name"]')?.value?.trim();
- var existing_value1 = $(condition_element).attr("data-existingvalue");
+ populate_condition_target( conditionTargetsSelect, conditionOperatorSelect?.value, [fieldId] );
- if ($.trim(existing_value1) !== '') {
- jQuery(condition_element).val(existing_value1);
+ if ( conditionTargetsSelect?.dataset?.existingvalue ) {
+ conditionTargetsSelect.value = conditionTargetsSelect?.dataset?.existingvalue;
}
+
+ // NOTE: Get all the locked operators. Unlock them to be eligible to show the upsell.
+ conditionOperatorSelect?.querySelectorAll( 'option' ).forEach( option => {
+ if ( ! option.disabled ) {
+ return;
+ }
+ proOperatorOptionsToLock.add( option.value );
+ option.disabled = false;
+ });
+
+ toggleOperatorFieldByTargetType( findFieldTypeById( conditionTargetsSelect?.value ), conditionOperatorSelect );
+
+ const optionsInput = conditionContainer.querySelector('[data-metatype="element_values"]');
+
+ updateTargetComparisonValueSelect(
+ conditionTargetsSelect,
+ conditionContainer,
+ optionsInput?.dataset?.existingvalue
+ );
});
});
+ }
+ /**
+ * Update the values of the operators selector and the comparison fields.
+ *
+ * NOTE: We are using a global listener since some node are dinamically created/cloned.
+ */
+ document.addEventListener('change', function(e) {
+ if ( ! e.target.matches('select[data-metatype="elements"]') ) {
+ return;
+ }
+ e.preventDefault();
+ const conditionContainer = e.target.closest('.webcontact-rules');
+ const conditionOperatorSelect = conditionContainer?.querySelector('[data-metatype="operators"]');
+ if ( ! conditionContainer || ! conditionOperatorSelect ) {
+ return;
+ }
+
+ toggleOperatorFieldByTargetType( findFieldTypeById(e.target?.value), conditionOperatorSelect );
+ updateTargetComparisonValueSelect( e.target, conditionContainer );
- // setting the existing conditional elements values
- $(".ppom-slider").each(function(i, item) {
-
- $(item).find('select[data-metatype="element_values"]').each(function(i, condition_element) {
-
- var div = $(this).closest('.webcontact-rules');
- var existing_value1 = $(condition_element).attr("data-existingvalue");
-
- div.find('select[data-metatype="elements"]').trigger('change');
- if ($.trim(existing_value1) !== '') {
- jQuery(condition_element).val(existing_value1);
- }
- });
- });
-
- }
-
+ const optionsInput = conditionContainer.querySelector('[data-metatype="element_values"]');
+ const constantInput = conditionContainer.querySelector('[data-metatype="element_constant"]');
+
+ // Reset values.
+ if ( constantInput ) {
+ constantInput.value = '';
+ }
+ if ( optionsInput ) {
+ optionsInput.value = '';
+ }
+ });
+
/**
28- validate API WooCommerce Product
**/
diff --git a/js/ppom-conditions-v2.js b/js/ppom-conditions-v2.js
index 5e8296c..e3c5fec 100644
--- a/js/ppom-conditions-v2.js
+++ b/js/ppom-conditions-v2.js
@@ -1,3 +1,5 @@
+// @ts-check
+
/**
* PPOM Conditional Version 2
* More Fast and Optimized
@@ -48,38 +50,37 @@ jQuery(function($) {
}, 100);
// $('form.cart').on('change', 'select, input[type="radio"], input[type="checkbox"]', function(ev) {
-
- $(".ppom-wrapper").on('change', 'select,input:radio,input:checkbox', function(e) {
-
+
+ function trigger_check_conditions( modifiedElement ) {
let value = null;
- if (($(this).is(':radio') || $(this).is(':checkbox'))) {
- value = this.checked ? $(this).val() : null;
+ if (modifiedElement.type === 'radio' || modifiedElement.type === 'checkbox') {
+ value = modifiedElement.checked ? modifiedElement.value : null;
+ } else {
+ value = modifiedElement.value;
}
- else {
-
- value = $(this).val();
- }
-
- const data_name = $(this).data('data_name');
- // console.log("Checking condition for ", data_name);
- ppom_check_conditions(data_name, function(element_dataname, event_type) {
- // console.log(`${element_dataname} ===> ${event_type}`);
- $.event.trigger({
- type: event_type,
- field: element_dataname,
- time: new Date()
+ const data_name = modifiedElement.dataset?.data_name;
+ ppom_check_conditions(data_name, (element_dataname, event_type) => {
+ const event = new CustomEvent(event_type, {
+ detail: {
+ field: element_dataname,
+ time: new Date()
+ }
});
+ document.dispatchEvent(event);
});
+ }
+
+ $(".ppom-wrapper").on('change', 'select, input:radio, input:checkbox, input[type="date"]', function(_e) {
+ trigger_check_conditions( this );
+ });
+
+ $(".ppom-wrapper").on('keyup', 'input:text, input[type="number"], input[type="email"]', function(_e) {
+ trigger_check_conditions( this );
});
$(document).on('ppom_hidden_fields_updated', function(e) {
ppom_fields_hidden_conditionally();
-
- // $("#conditionally_hidden").val(ppom_hidden_fields);
- // console.log(` hiddend field updated ==> ${e.field}`);
- // $("#conditionally_hidden").val(ppom_hidden_fields);
- // ppom_update_option_prices();
});
@@ -274,10 +275,8 @@ jQuery(function($) {
function ppom_check_conditions(data_name, callback) {
let is_matched = false;
- const ppom_type = jQuery(`.ppom-input[data-data_name="${data_name}"]`).data('type');
- const is_file = jQuery("a.file.ppom-input").length > 0;
let event_type, element_data_name;
-
+
jQuery(`div.ppom-cond-${data_name}`).each(function() {
// return this.data('cond-val1').match(/\w*-Back/);
// console.log(jQuery(this));
@@ -290,21 +289,30 @@ function ppom_check_conditions(data_name, callback) {
var matched_conditions = [];
let cond_elements = [];
for (var t = 1; t <= total_cond; t++) {
+ const targetFieldToCompare = jQuery(this).data(`cond-input${t}`)?.toString()?.toLowerCase()
+ const targetFieldValue = ppom_get_element_value(targetFieldToCompare);
- const cond_element = jQuery(this).data(`cond-input${t}`)?.toString()?.toLowerCase();
- const cond_val = jQuery(this).data(`cond-val${t}`).toString();
+ const selectOptionValue = jQuery(this).data(`cond-val${t}`)?.toString();
const operator = jQuery(this).data(`cond-operator${t}`);
- const field_val = ppom_get_element_value(cond_element);
-
- // const field_val = ppom_get_field_type(field_obj);
- // console.log(cond_element,field_val,cond_val);
- // if (cond_element !== data_name) continue;
- is_matched = ppom_compare_values(field_val, cond_val, operator);
- // console.log(`${data_name} TRIGGERS :: ${t} ***** ${element_data_name} ==> field value ${field_val} || cond_valu ${cond_val} || operator ${operator} || Binding ${binding} is_matched=>${is_matched}`);
+ const constantValue = jQuery(this).data(`cond-constant-val-${t}`)?.toString();
+ const betweenValueTo = jQuery(this).data(`cond-between-to-${t}`);
+ const betweenValueFrom = jQuery(this).data(`cond-between-from-${t}`);
+
+
+ is_matched = ppom_compare_values({
+ valueToCompare: targetFieldValue,
+ selectOptionToCompare: selectOptionValue,
+ constantValueToCompare: constantValue,
+ betweenValueInterval: {
+ from: betweenValueFrom,
+ to: betweenValueTo
+ },
+ operator
+ });
- if(is_matched) {
+ if ( is_matched ) {
matched = ++matched;
- cond_elements.push(cond_element);
+ cond_elements.push(targetFieldToCompare);
}
matched_conditions[element_data_name] = matched;
@@ -325,9 +333,9 @@ function ppom_check_conditions(data_name, callback) {
}
});
- if ( typeof callback == "function" )
+ if ( typeof callback == "function" ) {
callback(element_data_name, event_type);
- // return is_matched;
+ }
}
else if ( ! is_matched || matched_conditions[element_data_name] !== total_cond) {
@@ -350,9 +358,6 @@ function ppom_check_conditions(data_name, callback) {
callback(element_data_name, event_type);
}
}
-
- // return is_matched;
- // return jQuery(this).data('cond-val1') === jQuery(this).val();
});
}
@@ -408,26 +413,94 @@ function ppom_get_element_value(data_name) {
return element_value;
}
-function ppom_compare_values(v1, v2, operator) {
-
+/**
+ * Compares values based on the provided operator.
+ *
+ * @param {Object} args - The arguments object containing comparison parameters.
+ * @param {string} args.valueToCompare - The target value to compare.
+ * @param {string} args.selectOptionToCompare - The select option value to compare.
+ * @param {string} args.constantValueToCompare - The constant value to compare.
+ * @param {{to: string, from: string}} args.betweenValueInterval - The between interval.
+ * @param {string} args.operator - The operator used for comparison.
+ * @returns {boolean} - The result of the comparison.
+ */
+function ppom_compare_values( args ) {
+ const { valueToCompare, selectOptionToCompare, constantValueToCompare, operator, betweenValueInterval } = args;
let result = false;
switch (operator) {
case 'is':
- if( Array.isArray(v1) ) {
- result = jQuery.inArray(v2, v1) !== -1 ? true : false;
- }else{
- result = v1 === v2 ? true : false;
+ if ( Array.isArray(valueToCompare) ) {
+ result = jQuery.inArray(selectOptionToCompare, valueToCompare) !== -1;
+ } else {
+ result = valueToCompare === selectOptionToCompare;
+ if ( !selectOptionToCompare && constantValueToCompare ) {
+ result = valueToCompare === constantValueToCompare
+ }
}
break;
+
case 'not':
- result = v1 !== v2 ? true : false;
+ result = valueToCompare !== selectOptionToCompare;
+ if ( !selectOptionToCompare && constantValueToCompare ) {
+ result = valueToCompare !== constantValueToCompare
+ }
break;
case 'greater than':
- result = parseFloat(v1) > parseFloat(v2) ? true : false;
+ result = parseFloat(valueToCompare) > parseFloat(selectOptionToCompare);
+ if ( !selectOptionToCompare && constantValueToCompare ) {
+ result = parseFloat(valueToCompare) > parseFloat(constantValueToCompare)
+ }
break;
+
case 'less than':
- result = parseFloat(v1) < parseFloat(v2) ? true : false;
+ result = parseFloat(valueToCompare) < parseFloat(selectOptionToCompare);
+ if ( !selectOptionToCompare && constantValueToCompare ) {
+ result = parseFloat(valueToCompare) < parseFloat(constantValueToCompare)
+ }
+ break;
+
+ case 'any':
+ result = valueToCompare !== undefined && valueToCompare !== null && valueToCompare !== '';
+ break;
+
+ case 'empty':
+ result = valueToCompare === undefined || valueToCompare === null || valueToCompare === '';
+ break;
+
+ case 'between':
+ result = (
+ parseFloat(valueToCompare) >= parseFloat( betweenValueInterval.from ) &&
+ parseFloat(valueToCompare) <= parseFloat( betweenValueInterval.to )
+ );
+ break;
+
+ case 'number-multiplier':
+ result = parseFloat(valueToCompare) % parseFloat(constantValueToCompare) === 0;
+ break;
+
+ case 'even-number':
+ result = parseFloat(valueToCompare) % 2 === 0;
+ break;
+
+ case 'odd-number':
+ result = parseFloat(valueToCompare) % 2 !== 0;
+ break;
+
+ case 'contains':
+ result = valueToCompare?.includes(constantValueToCompare);
+ break;
+
+ case 'not contains':
+ result = !valueToCompare?.includes(constantValueToCompare);
+ break;
+
+ case 'regex':
+ if ( typeof constantValueToCompare === 'string' ) {
+ const [_, pattern, flags] = constantValueToCompare.split('/');
+ const regex = new RegExp(pattern || constantValueToCompare, flags);
+ result = regex.test(valueToCompare);
+ }
break;
default: