Files
wc-licensed-product/assets/js/versions.js

379 lines
14 KiB
JavaScript
Raw Normal View History

/**
* WC Licensed Product - Version Management
*
* @package Jeremias\WcLicensedProduct
*/
(function($) {
'use strict';
var WCLicensedProductVersions = {
mediaFrame: null,
init: function() {
this.bindEvents();
},
bindEvents: function() {
$('#add-version-btn').on('click', this.addVersion);
$(document).on('click', '.delete-version-btn', this.deleteVersion);
$(document).on('click', '.toggle-version-btn', this.toggleVersion);
// Media uploader events
$('#upload-version-file-btn').on('click', this.openMediaUploader.bind(this));
$('#remove-version-file-btn').on('click', this.removeSelectedFile);
// Checksum file events
$('#select-checksum-file-btn').on('click', this.triggerChecksumFileSelect);
$('#new_checksum_file').on('change', this.onChecksumFileSelected);
$('#remove-checksum-file-btn').on('click', this.removeChecksumFile);
// Listen for product type changes
$('#product-type').on('change', this.onProductTypeChange);
// Initial check for product type (handles page load for new products)
this.onProductTypeChange();
},
onProductTypeChange: function() {
var productType = $('#product-type').val();
var $metaBox = $('#wc_licensed_product_versions');
if (productType === 'licensed') {
$metaBox.show();
} else {
$metaBox.hide();
}
},
/**
* Open WordPress media uploader
*/
openMediaUploader: function(e) {
e.preventDefault();
var self = this;
// If frame already exists, open it
if (this.mediaFrame) {
this.mediaFrame.open();
return;
}
// Create media frame
this.mediaFrame = wp.media({
title: wcLicensedProductVersions.strings.selectFile,
button: {
text: wcLicensedProductVersions.strings.useThisFile
},
multiple: false,
library: {
type: ['application/zip', 'application/x-zip-compressed', 'application/octet-stream']
}
});
// When file is selected
this.mediaFrame.on('select', function() {
var attachment = self.mediaFrame.state().get('selection').first().toJSON();
// Set attachment ID
$('#new_attachment_id').val(attachment.id);
// Show filename
$('#selected_file_name').text(attachment.filename);
$('#remove-version-file-btn').show();
// Show SHA256 hash field
$('#sha256-hash-row').show();
// Try to extract version from filename
var extractedVersion = self.extractVersionFromFilename(attachment.filename);
if (extractedVersion && !$('#new_version').val().trim()) {
$('#new_version').val(extractedVersion);
}
});
this.mediaFrame.open();
},
/**
* Remove selected file
*/
removeSelectedFile: function(e) {
e.preventDefault();
$('#new_attachment_id').val('');
$('#selected_file_name').text('');
$('#remove-version-file-btn').hide();
// Hide and clear checksum file field
$('#sha256-hash-row').hide();
$('#new_checksum_file').val('');
$('#selected_checksum_name').text('');
$('#remove-checksum-file-btn').hide();
},
/**
* Trigger checksum file input click
*/
triggerChecksumFileSelect: function(e) {
e.preventDefault();
$('#new_checksum_file').trigger('click');
},
/**
* Handle checksum file selection
*/
onChecksumFileSelected: function(e) {
var file = e.target.files[0];
if (file) {
$('#selected_checksum_name').text(file.name);
$('#remove-checksum-file-btn').show();
} else {
$('#selected_checksum_name').text('');
$('#remove-checksum-file-btn').hide();
}
},
/**
* Remove selected checksum file
*/
removeChecksumFile: function(e) {
e.preventDefault();
$('#new_checksum_file').val('');
$('#selected_checksum_name').text('');
$('#remove-checksum-file-btn').hide();
},
/**
* Read checksum from uploaded file
* Supports formats: "hash filename" or just "hash"
*/
readChecksumFile: function(file) {
return new Promise(function(resolve, reject) {
if (!file) {
resolve('');
return;
}
var reader = new FileReader();
reader.onload = function(e) {
var content = e.target.result.trim();
// Extract hash from content (format: "hash filename" or just "hash")
var match = content.match(/^([a-fA-F0-9]{64})/);
if (match) {
resolve(match[1].toLowerCase());
} else {
reject(new Error(wcLicensedProductVersions.strings.invalidChecksumFile || 'Invalid checksum file format'));
}
};
reader.onerror = function() {
reject(new Error(wcLicensedProductVersions.strings.checksumReadError || 'Failed to read checksum file'));
};
reader.readAsText(file);
});
},
/**
* Extract version from filename
* Supports patterns like: plugin-v1.2.3.zip, plugin-1.2.3.zip, v1.2.3.zip
*/
extractVersionFromFilename: function(filename) {
// Remove extension
var basename = filename.replace(/\.[^/.]+$/, '');
// Try various patterns
var patterns = [
/[_-]v?(\d+\.\d+\.\d+)$/i, // ends with -v1.2.3 or -1.2.3
/[_-]v?(\d+\.\d+\.\d+)[_-]/i, // contains -v1.2.3- or -1.2.3-
/^v?(\d+\.\d+\.\d+)$/i // just version number
];
for (var i = 0; i < patterns.length; i++) {
var match = basename.match(patterns[i]);
if (match) {
return match[1];
}
}
return null;
},
addVersion: function(e) {
e.preventDefault();
var self = WCLicensedProductVersions;
var $btn = $(this);
var $spinner = $btn.siblings('.spinner');
var productId = $btn.data('product-id');
var version = $('#new_version').val().trim();
var releaseNotes = $('#new_release_notes').val().trim();
var attachmentId = $('#new_attachment_id').val();
var checksumFile = $('#new_checksum_file')[0].files[0];
// Validate version
if (!version) {
alert(wcLicensedProductVersions.strings.versionRequired);
return;
}
if (!/^\d+\.\d+\.\d+$/.test(version)) {
alert(wcLicensedProductVersions.strings.versionInvalid);
return;
}
$btn.prop('disabled', true);
$spinner.addClass('is-active');
// Read checksum file if provided, then submit
self.readChecksumFile(checksumFile).then(function(fileHash) {
$.ajax({
url: wcLicensedProductVersions.ajaxUrl,
type: 'POST',
data: {
action: 'wc_licensed_product_add_version',
nonce: wcLicensedProductVersions.nonce,
product_id: productId,
version: version,
release_notes: releaseNotes,
attachment_id: attachmentId,
file_hash: fileHash
},
success: function(response) {
if (response.success) {
// Remove "no versions" row if present
$('#versions-table tbody .no-versions').remove();
// Add new row to table
$('#versions-table tbody').prepend(response.data.html);
// Clear form
$('#new_version').val('');
$('#new_release_notes').val('');
$('#new_attachment_id').val('');
$('#selected_file_name').text('');
$('#remove-version-file-btn').hide();
$('#sha256-hash-row').hide();
$('#new_checksum_file').val('');
$('#selected_checksum_name').text('');
$('#remove-checksum-file-btn').hide();
} else {
alert(response.data.message || wcLicensedProductVersions.strings.error);
}
},
error: function() {
alert(wcLicensedProductVersions.strings.error);
},
complete: function() {
$btn.prop('disabled', false);
$spinner.removeClass('is-active');
}
});
}).catch(function(error) {
alert(error.message);
$btn.prop('disabled', false);
$spinner.removeClass('is-active');
});
},
deleteVersion: function(e) {
e.preventDefault();
if (!confirm(wcLicensedProductVersions.strings.confirmDelete)) {
return;
}
var $btn = $(this);
var $row = $btn.closest('tr');
var versionId = $btn.data('version-id');
$btn.prop('disabled', true);
$.ajax({
url: wcLicensedProductVersions.ajaxUrl,
type: 'POST',
data: {
action: 'wc_licensed_product_delete_version',
nonce: wcLicensedProductVersions.nonce,
version_id: versionId
},
success: function(response) {
if (response.success) {
$row.fadeOut(300, function() {
$(this).remove();
// Show "no versions" message if table is empty
if ($('#versions-table tbody tr').length === 0) {
$('#versions-table tbody').append(
'<tr class="no-versions"><td colspan="6">' +
'No versions found. Add your first version above.' +
'</td></tr>'
);
}
});
} else {
alert(response.data.message || wcLicensedProductVersions.strings.error);
$btn.prop('disabled', false);
}
},
error: function() {
alert(wcLicensedProductVersions.strings.error);
$btn.prop('disabled', false);
}
});
},
toggleVersion: function(e) {
e.preventDefault();
var $btn = $(this);
var $row = $btn.closest('tr');
var versionId = $btn.data('version-id');
var currentlyActive = $btn.data('active') === 1 || $btn.data('active') === '1';
$btn.prop('disabled', true);
$.ajax({
url: wcLicensedProductVersions.ajaxUrl,
type: 'POST',
data: {
action: 'wc_licensed_product_toggle_version',
nonce: wcLicensedProductVersions.nonce,
version_id: versionId,
currently_active: currentlyActive ? 1 : 0
},
success: function(response) {
if (response.success) {
var isActive = response.data.isActive;
var $status = $row.find('.version-status');
// Update status badge
$status
.removeClass('version-status-active version-status-inactive')
.addClass('version-status-' + (isActive ? 'active' : 'inactive'))
.text(isActive ? 'Active' : 'Inactive');
// Update button
$btn
.data('active', isActive ? 1 : 0)
.text(isActive ? 'Deactivate' : 'Activate');
} else {
alert(response.data.message || wcLicensedProductVersions.strings.error);
}
},
error: function() {
alert(wcLicensedProductVersions.strings.error);
},
complete: function() {
$btn.prop('disabled', false);
}
});
}
};
$(document).ready(function() {
WCLicensedProductVersions.init();
});
})(jQuery);