217 lines
11 KiB
Plaintext
217 lines
11 KiB
Plaintext
jQuery(function($){
|
|
|
|
$('a[href="admin.php?page=formipay-products"]').addClass('current').closest('li').addClass('current');
|
|
|
|
function autoset_variation_name() {
|
|
|
|
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
|
|
$.each(repeater_single, function(key, parent){
|
|
var repeater_child = $(parent).find('[field_native_name="product_variation_attributes"]');
|
|
var attribute_name = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_name"]`).val();
|
|
var attribute_type = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_type"]`).val();
|
|
var repeater_child_single = repeater_child.find('.wpcfto-repeater-single');
|
|
$.each(repeater_child_single, function(index, child){
|
|
var label_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_label"]`);
|
|
var name_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_name"]`);
|
|
var color_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_color"]`);
|
|
var color_field_row = color_field.closest('.wpcfto-repeater-field');
|
|
|
|
if(attribute_type == 'color'){
|
|
color_field_row.show();
|
|
}else{
|
|
color_field_row.hide();
|
|
}
|
|
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
$(document).on('change blur', '[field_native_name_inner="variation_label"] input', function(){
|
|
autoset_variation_name();
|
|
});
|
|
|
|
$(document).on('click', '.stm_metaboxes_grid .stm_metaboxes_grid__inner .wpcfto-repeater .addArea', function() {
|
|
autoset_variation_name();
|
|
});
|
|
|
|
var onMetaboxLoaded = setInterval(() => {
|
|
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
|
|
if(repeater_single.length > 0){
|
|
autoset_variation_name();
|
|
clearInterval(onMetaboxLoaded);
|
|
}
|
|
}, 250);
|
|
|
|
var waitForTable = setInterval(() => {
|
|
if ($('#product-variables-table').length > 0) {
|
|
clearInterval(waitForTable);
|
|
|
|
new Vue({
|
|
el: '#product-variables-table',
|
|
data() {
|
|
return {
|
|
tableRows: [],
|
|
deletedKeys: [],
|
|
isPhysical: window.product_details?.product_is_physical || false,
|
|
jsonValue: '[]',
|
|
attributeRepeaterWatcher: null,
|
|
_debounceTimer: null,
|
|
productType: window.product_details?.product_type || 'digital', // default, will update on mount
|
|
productCurrencyRaw: window.product_details?.product_currency || 'USD:::United States dollar:::$',
|
|
currencyDecimalDigits: parseInt(window.product_details?.product_currency_decimal_digits) || 2,
|
|
currencyDecimalSymbol: window.product_details?.product_currency_decimal_symbol || '.',
|
|
currencyThousandSeparator: window.product_details?.product_currency_thousand_separator || ',',
|
|
};
|
|
},
|
|
async mounted() {
|
|
|
|
await this.loadProductVariables();
|
|
this.setupAttributeRepeaterSync();
|
|
|
|
// Listen for changes on product_type radios to update reactive data
|
|
const radios = document.querySelectorAll('input[name="product_type"]');
|
|
radios.forEach(radio => {
|
|
radio.addEventListener('change', e => {
|
|
this.productType = e.target.value;
|
|
this.isPhysical = e.target.value == 'physical';
|
|
this.rebuildTable(); // Rebuild the table on type change
|
|
});
|
|
});
|
|
|
|
// Listen for changes on product_currency select
|
|
const currencySelect = document.querySelector('select[name="product_currency"]');
|
|
if (currencySelect) {
|
|
currencySelect.addEventListener('change', (e) => {
|
|
this.productCurrencyRaw = e.target.value;
|
|
});
|
|
}
|
|
|
|
// Initialize currency values
|
|
this.productCurrencyRaw = window.product_details?.product_currency || 'USD:::United States dollar:::$';
|
|
},
|
|
beforeDestroy() {
|
|
if (this.attributeRepeaterWatcher) {
|
|
this.attributeRepeaterWatcher.disconnect();
|
|
}
|
|
},
|
|
methods: {
|
|
async loadProductVariables() {
|
|
const postId = window.formipayProductId || $('input[name="post_ID"]').val();
|
|
if (!postId) {
|
|
await this.buildFromAttributes();
|
|
return;
|
|
}
|
|
try {
|
|
const res = await $.ajax({
|
|
url: ajaxurl,
|
|
method: 'POST',
|
|
data: { action: 'get_product_variables', post_id: postId }
|
|
});
|
|
if (res.success && Array.isArray(res.data) && res.data.length) {
|
|
this.tableRows = res.data;
|
|
this.deletedKeys = [];
|
|
this.updateJson();
|
|
} else {
|
|
await this.buildFromAttributes();
|
|
}
|
|
} catch {
|
|
await this.buildFromAttributes();
|
|
}
|
|
},
|
|
async buildFromAttributes() {
|
|
try {
|
|
const attributes = await this.getAttributeRepeaterData();
|
|
if (!attributes.length) {
|
|
this.tableRows = [];
|
|
this.updateJson();
|
|
return;
|
|
}
|
|
const combinations = this.getAllCombinations(attributes);
|
|
const filtered = combinations.filter(c => !this.deletedKeys.includes(c.key));
|
|
const newRows = filtered.map(c => {
|
|
const existing = this.tableRows.find(r => r.key === c.key);
|
|
return existing ? Object.assign(existing, { name: c.label }) : {
|
|
key: c.key,
|
|
name: c.label,
|
|
stock: '',
|
|
price: 0,
|
|
sale: 0,
|
|
weight: 0,
|
|
active: true,
|
|
};
|
|
});
|
|
this.tableRows = newRows;
|
|
this.updateJson();
|
|
} catch (e) {
|
|
this.tableRows = [];
|
|
this.updateJson();
|
|
}
|
|
},
|
|
getAttributeRepeaterData() {
|
|
return new Promise((resolve, reject) => {
|
|
let attempts = 0;
|
|
const maxAttempts = 100;
|
|
const interval = setInterval(() => {
|
|
const el = $('#variation-product_variation_attributes');
|
|
if (el.length && el.val()) {
|
|
try {
|
|
const data = JSON.parse(el.val());
|
|
clearInterval(interval);
|
|
resolve(data);
|
|
} catch {
|
|
clearInterval(interval);
|
|
reject(new Error('Invalid JSON in attribute repeater'));
|
|
}
|
|
} else if (++attempts >= maxAttempts) {
|
|
clearInterval(interval);
|
|
reject(new Error('Attribute repeater data not found'));
|
|
}
|
|
}, 50);
|
|
});
|
|
},
|
|
getAllCombinations(attributes) {
|
|
if (!attributes.length) return [];
|
|
const attrVars = attributes.map(attr =>
|
|
(attr.attribute_variations || []).map(v => ({ label: v.variation_label }))
|
|
).filter(arr => arr.length > 0);
|
|
if (!attrVars.length) return [];
|
|
const combine = (arrs) => arrs.reduce((a, b) => a.flatMap(d => b.map(e => [].concat(d, e))));
|
|
const combos = combine(attrVars);
|
|
return combos.map(combo => {
|
|
const labels = Array.isArray(combo) ? combo.map(c => c.label) : [combo.label];
|
|
return { key: labels.join('||'), label: labels.join(' - ') };
|
|
});
|
|
},
|
|
setupAttributeRepeaterSync() {
|
|
const target = document.getElementById('variation-product_variation_attributes');
|
|
if (!target) return;
|
|
const observer = new MutationObserver(mutations => {
|
|
for (const m of mutations) {
|
|
if (m.type === 'attributes' && m.attributeName === 'value') {
|
|
clearTimeout(this._debounceTimer);
|
|
this._debounceTimer = setTimeout(() => this.buildFromAttributes(), 200);
|
|
}
|
|
}
|
|
});
|
|
observer.observe(target, { attributes: true, attributeFilter: ['value'] });
|
|
this.attributeRepeaterWatcher = observer;
|
|
},
|
|
updateJson() {
|
|
this.jsonValue = JSON.stringify(this.tableRows);
|
|
},
|
|
rebuildTable() {
|
|
this.loadProductVariables();
|
|
}
|
|
},
|
|
watch: {
|
|
tableRows: {
|
|
handler() { this.updateJson(); },
|
|
deep: true
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}, 250);
|
|
|
|
}); |