AugustCover image generated, processed, and saved successfully! document.addEventListener(‘DOMContentLoaded’, async function() {
const projectSelect = document.getElementById(‘projectSelect’);
const categoriesContainer = document.getElementById(‘categoriesContainer’);
const publishArticleBtn = document.getElementById(‘publishArticleBtn’);
const articleContent = document.getElementById(‘articleContent’);
const publishMessage = document.getElementById(‘publishMessage’);
const publishMessageText = document.getElementById(‘publishMessageText’); // Get the text span
const loadingSpinner = document.querySelector(‘#publishMessage .loading-spinner’); // Get the spinner
const addCoverImageCheckbox = document.getElementById(‘addCoverImageCheckbox’);
const imageGenerationControls = document.getElementById(‘imageGenerationControls’);
const generatedImagePanel = document.getElementById(‘generatedImagePanel’);
const aspectRatioSelect = document.getElementById(‘aspectRatioSelect’);
const generateImageBtn = document.getElementById(‘generateImageBtn’);
const imageDisplayArea = document.getElementById(‘imageDisplayArea’);
const customPromptInput = document.getElementById(‘customPrompt’); // Get the custom prompt textarea
let generatedImageBase64 = null; // Variable to store the generated image data
const researchId = “185”; // Pass research_id from PHP to JS
const initialCoverImage = null; // Pass existing cover image data // The h2 tag for the title is now expected to be *inside* articleContent
let articleTitleElement = null; // Load custom prompt from local storage on page load
const savedCustomPrompt = localStorage.getItem(‘customImagePrompt’);
if (savedCustomPrompt) {
customPromptInput.value = savedCustomPrompt;
} // Save custom prompt to local storage on input change
customPromptInput.addEventListener(‘input’, function() {
localStorage.setItem(‘customImagePrompt’, this.value);
}); // Function to toggle aspect ratio and generate image button visibility
addCoverImageCheckbox.addEventListener(‘change’, function() {
if (this.checked) {
imageGenerationControls.style.display = ‘block’;
generatedImagePanel.style.display = ‘block’; // Show the image panel as well
aspectRatioSelect.value = ’16:9′; // Set default aspect ratio
} else {
imageGenerationControls.style.display = ‘none’;
generatedImagePanel.style.display = ‘none’; // Hide the image panel
// Clear previously generated image if checkbox is unchecked
imageDisplayArea.innerHTML = ”; // Clear the image display area
generatedImageBase64 = null;
}
}); let messageTimeout; // Declare a variable to hold the timeout function showPublishMessage(msg, type) {
clearTimeout(messageTimeout); // Clear any existing timeout
publishMessage.style.opacity = ‘1’; // Ensure full visibility
publishMessage.style.display = ‘block’; // Show the message
publishMessage.classList.remove(‘success’, ‘error’); // Remove previous type classes
publishMessage.classList.add(type);
publishMessageText.innerHTML = msg; // Update text content
loadingSpinner.classList.remove(‘show’); // Hide spinner for success/error messages
} function showPublishLoading(msg) {
clearTimeout(messageTimeout); // Clear any existing timeout
publishMessage.style.opacity = ‘1’; // Ensure full visibility
publishMessage.style.display = ‘flex’; // Use flexbox to align spinner and text
publishMessage.alignItems = ‘center’; // Vertically align items
publishMessage.justifyContent = ‘center’; // Horizontally align items
publishMessage.classList.remove(‘success’, ‘error’); // Remove previous type classes
publishMessage.classList.add(‘message’);
publishMessageText.textContent = msg; // Update text content
loadingSpinner.classList.add(‘show’); // Show spinner
} // Function to update publish button state
function updatePublishButtonState() {
const selectedProject = projectSelect.value;
const selectedCategories = categoriesContainer.querySelectorAll(‘input[type=”checkbox”]:checked’);
publishArticleBtn.disabled = !(selectedProject && selectedCategories.length > 0);
} // Function to generate the cover image
async function generateCoverImage() {
const firstH2 = articleContent.querySelector(‘h2’);
let imagePrompt = ”;
if (firstH2) {
imagePrompt = firstH2.textContent.trim();
}
const aspectRatio = aspectRatioSelect.value;
const customPrompt = customPromptInput.value.trim(); // Get custom prompt value if (!imagePrompt) {
showPublishMessage(‘Could not find a title (h2) in the article content to generate an image prompt.’, ‘error’);
return;
} showPublishLoading(‘Generating cover image…’);
try {
const imageFormData = new URLSearchParams();
imageFormData.append(‘prompt’, imagePrompt);
imageFormData.append(‘aspectRatio’, aspectRatio);
if (customPrompt) {
imageFormData.append(‘custom_prompt’, customPrompt); // Append custom prompt if available
} const imageResponse = await fetch(‘generate-image-api.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’
},
body: imageFormData
}); const imageData = await imageResponse.json(); if (imageData.base64Image) {
showPublishLoading(‘Processing and compressing generated image…’);
const processImageResponse = await fetch(‘apis/process-image.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({ image_base64: imageData.base64Image })
});
const processedImageData = await processImageResponse.json(); if (processedImageData.success) {
generatedImageBase64 = processedImageData.base64_image;
let imgElement = document.getElementById(‘generatedCoverImage’);
if (!imgElement) {
imgElement = document.createElement(‘img’);
imgElement.id = ‘generatedCoverImage’;
imgElement.className = ‘w-full h-auto rounded-lg’; // Tailwind classes for styling
imageDisplayArea.innerHTML = ”; // Clear previous image
imageDisplayArea.appendChild(imgElement);
}
imgElement.src = `data:image/jpeg;base64,${generatedImageBase64}`; // Display as JPEG
imgElement.alt = ‘Generated Cover Image (Processed)’;
showPublishMessage(‘Cover image generated and processed successfully! Saving image data…’, ‘success’); // Save the processed and compressed image data to the database
try {
const saveImageResponse = await fetch(‘apis/save-image-data.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({
research_id: researchId,
image_base64: generatedImageBase64
})
});
const saveImageResult = await saveImageResponse.json();
if (saveImageResult.success) {
showPublishMessage(‘Cover image generated, processed, and saved successfully!’, ‘success’);
} else {
showPublishMessage(`Cover image generated and processed, but failed to save: ${saveImageResult.message || ‘Unknown error’}`, ‘error’);
}
} catch (saveError) {
console.error(‘Save image data fetch error:’, saveError);
showPublishMessage(`Cover image generated and processed, but network error during save: ${saveError.message}`, ‘error’);
} messageTimeout = setTimeout(() => {
publishMessage.style.opacity = ‘0’; // Start fade out
setTimeout(() => {
publishMessage.style.display = ‘none’; // Hide after fade
}, 500); // Match CSS transition duration
}, 6000); // Hide after 6 seconds
} else {
showPublishMessage(`Failed to process generated image: ${processedImageData.message || ‘Unknown error’}`, ‘error’);
generatedImageBase64 = null;
}
} else {
showPublishMessage(`Failed to generate image: ${imageData.error || ‘Unknown error’}`, ‘error’);
generatedImageBase64 = null;
}
} catch (error) {
console.error(‘Image generation fetch error:’, error);
showPublishMessage(`Network error during image generation: ${error.message}`, ‘error’);
generatedImageBase64 = null;
}
} // Event listener for the new generate image button
generateImageBtn.addEventListener(‘click’, function() {
publishMessage.style.display = ‘none’; // Hide message immediately on new generation
publishMessage.style.opacity = ‘0’; // Reset opacity
clearTimeout(messageTimeout); // Clear any pending hide timeouts
loadingSpinner.classList.remove(‘show’); // Hide spinner using class
generateCoverImage();
}); projectSelect.addEventListener(‘change’, function() {
const selectedOption = this.options[this.selectedIndex];
const categoriesData = selectedOption.dataset.categories; categoriesContainer.innerHTML = ”; // Clear previous categories
publishArticleBtn.disabled = true;
publishMessage.style.display = ‘none’; // Hide the message if (categoriesData) {
try {
const categories = JSON.parse(categoriesData);
if (Array.isArray(categories) && categories.length > 0) {
categories.forEach(category => {
const checkboxDiv = document.createElement(‘div’);
checkboxDiv.className = ‘flex items-center’;
const checkbox = document.createElement(‘input’);
checkbox.type = ‘checkbox’;
checkbox.id = `category-${category.id}`;
checkbox.value = category.id;
checkbox.className = ‘form-checkbox h-4 w-4 text-blue-600 transition duration-150 ease-in-out’;
checkbox.addEventListener(‘change’, updatePublishButtonState); // Add listener const label = document.createElement(‘label’);
label.htmlFor = `category-${category.id}`;
label.className = ‘ml-2 text-gray-700’;
label.textContent = category.name; checkboxDiv.appendChild(checkbox);
checkboxDiv.appendChild(label);
categoriesContainer.appendChild(checkboxDiv);
});
// Initial check for button state after categories are loaded
updatePublishButtonState();
} else {
categoriesContainer.innerHTML = ‘ No categories available for this project. ‘;
showPublishMessage(‘No categories available for this project.’, ‘error’);
}
} catch (e) {
console.error(‘Error parsing categories JSON:’, e);
categoriesContainer.innerHTML = ‘ Error loading categories. ‘;
showPublishMessage(‘Error loading categories.’, ‘error’);
}
} else {
categoriesContainer.innerHTML = ‘ Select a project to load categories. ‘;
}
}); publishArticleBtn.addEventListener(‘click’, async function() {
const selectedProjectOption = projectSelect.options[projectSelect.selectedIndex];
const projectId = selectedProjectOption.value;
const publishingUrl = selectedProjectOption.dataset.publishing_url;
const apikey = selectedProjectOption.dataset.apikey;
let attachmentId = null; // Optional attachment_id, will be set later if available const selectedCategoryCheckboxes = categoriesContainer.querySelectorAll(‘input[type=”checkbox”]:checked’);
const categoryIds = Array.from(selectedCategoryCheckboxes).map(cb => cb.value).join(‘,’); if (!projectId || !categoryIds || !publishingUrl || !apikey) {
showPublishMessage(‘Please select a project and at least one category.’, ‘error’);
return;
} // Get the first h2 tag inside the articleContent div for the title
articleTitleElement = articleContent.querySelector(‘h2’);
let title = ”;
if (articleTitleElement) {
const titleParser = new DOMParser();
const parsedTitleDoc = titleParser.parseFromString(articleTitleElement.innerHTML, ‘text/html’);
title = parsedTitleDoc.body.textContent.trim();
} else {
// Fallback if no h2 is found inside content, use the research ID as before
title = document.getElementById(‘articleTitle’).textContent.replace(‘Research ID: ‘, ”).trim();
} // The content is already HTML. If issues persist, consider server-side sanitization or further inspection of the HTML structure.
const content = articleContent.innerHTML; showPublishLoading(‘Publishing article…’); // — New logic for image upload before article publishing —
if (generatedImageBase64) {
showPublishLoading(‘Uploading cover image…’);
try {
const imageUploadResponse = await fetch(‘apis/upload-cover-image-to-server.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({
image_base64: generatedImageBase64, // Use the already compressed image
image_name: title.replace(/[^a-z0-9]/gi, ‘-‘).toLowerCase(), // Sanitize title for image name
image_extension: ‘jpeg’, // Already compressed to JPEG
post_title: title,
post_content: content.substring(0, 200) // Use a snippet of content
})
});
const imageUploadResult = await imageUploadResponse.json(); if (imageUploadResult.success && imageUploadResult.data && imageUploadResult.data.attachment_id) {
attachmentId = imageUploadResult.data.attachment_id;
showPublishLoading(‘Cover image uploaded. Publishing article…’);
} else {
showPublishMessage(`Failed to upload cover image: ${imageUploadResult.message || ‘Unknown error’}`, ‘error’);
return; // Stop publishing if image upload fails
}
} catch (imageUploadError) {
console.error(‘Image upload fetch error:’, imageUploadError);
showPublishMessage(`Network error during image upload: ${imageUploadError.message}`, ‘error’);
return; // Stop publishing if image upload fails
}
}
// — End new logic for image upload — const formData = new URLSearchParams();
formData.append(‘title’, title);
formData.append(‘content’, content);
formData.append(‘categoryids’, categoryIds);
formData.append(‘status’, ‘draft’);
formData.append(‘apikey’, apikey);
if (attachmentId) { // Conditionally add attachment_id if it exists
formData.append(‘attachment_id’, attachmentId);
} try {
const response = await fetch(publishingUrl, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’
},
body: formData
}); const result = await response.json(); if (result.success) {
showPublishMessage(`Article published successfully! Post ID: ${result.post_id}. View Post`, ‘success’);
// Update the is_published status in the database
fetch(‘update_publish_status.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’
},
body: `research_id=185&status=published`
}).then(response => response.json())
.then(data => {
if (data.success) {
console.log(‘Publication status updated in DB.’);
// Update the displayed status on the page
const publicationStatusElement = document.getElementById(‘publicationStatus’);
if (publicationStatusElement) {
publicationStatusElement.textContent = ‘Published’;
publicationStatusElement.classList.remove(‘status-unpublished’);
publicationStatusElement.classList.add(‘status-published’);
}
} else {
console.error(‘Failed to update publication status in DB:’, data.message);
}
}).catch(error => {
console.error(‘Error updating publication status in DB:’, error);
});
} else {
showPublishMessage(`Failed to publish article: ${result.message || ‘Unknown error’}`, ‘error’);
}
} catch (error) {
console.error(‘Publish article fetch error:’, error);
showPublishMessage(`Network error during publishing: ${error.message}`, ‘error’);
}
}); // Check for existing cover image on page load
if (initialCoverImage) {
// When loading an existing image, we should also process it to ensure it’s compressed
// This assumes the initialCoverImage might not be compressed or in the desired format
showPublishLoading(‘Processing existing cover image…’);
const processExistingImageResponse = await fetch(‘apis/process-image.php’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’
},
body: JSON.stringify({ image_base64: initialCoverImage })
});
const processedExistingImageData = await processExistingImageResponse.json(); if (processedExistingImageData.success) {
generatedImageBase64 = processedExistingImageData.base64_image;
let imgElement = document.createElement(‘img’);
imgElement.id = ‘generatedCoverImage’;
imgElement.className = ‘w-full h-auto rounded-lg’;
imageDisplayArea.innerHTML = ”;
imageDisplayArea.appendChild(imgElement);
imgElement.src = `data:image/jpeg;base64,${generatedImageBase64}`; // Display as JPEG
imgElement.alt = ‘Existing Cover Image (Processed)’;
showPublishMessage(‘Existing cover image processed successfully!’, ‘success’);
} else {
console.error(‘Failed to process existing cover image:’, processedExistingImageData.message);
// Fallback to original if processing fails, but log the error
generatedImageBase64 = initialCoverImage;
let imgElement = document.createElement(‘img’);
imgElement.id = ‘generatedCoverImage’;
imgElement.className = ‘w-full h-auto rounded-lg’;
imageDisplayArea.innerHTML = ”;
imageDisplayArea.appendChild(imgElement);
imgElement.src = `data:image/png;base64,${generatedImageBase64}`; // Display as PNG if processing failed
imgElement.alt = ‘Existing Cover Image (Original)’;
showPublishMessage(‘Failed to process existing cover image, displaying original.’, ‘error’);
} addCoverImageCheckbox.checked = true;
imageGenerationControls.style.display = ‘block’;
generatedImagePanel.style.display = ‘block’;
}
}); |