Files
formipay-public/admin/assets/js/admin-product-editor.jsbak
2025-08-21 20:39:34 +07:00

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);
});