//import * as avif from '@jsquash/avif'; // TBD //import * as webp from '@jsquash/webp'; // TBD import * as jpeg from '@jsquash/jpeg'; import * as png from '@jsquash/png'; import optimise from '@jsquash/oxipng/optimise'; const { __ } = wp.i18n; // Import __() from wp.i18n (function () { const bulkBtn = document.querySelector("input[name='squeeze_bulk']") const bulkLogInput = document.querySelector("[name='squeeze_bulk_log']") const squeeze_bulk_ids = document.querySelector("input[name='squeeze_bulk_ids']")?.value ?? null; const uncompressedIDs = squeeze_bulk_ids ? squeeze_bulk_ids.split(",") : []; async function decode(sourceType, fileBuffer) { switch (sourceType) { //case 'avif': // return await avif.decode(fileBuffer); case 'jpeg': return await jpeg.decode(fileBuffer); case 'png': return await png.decode(fileBuffer); //case 'webp': // return await webp.decode(fileBuffer); default: throw new Error(`Unknown source type: ${sourceType}`); } } async function encode(outputType, imageData) { const options = JSON.parse(squeeze.options); switch (outputType) { //case 'avif': // return await avif.encode(imageData); case 'jpeg': const jpegOptions = {} for (const [key, value] of Object.entries(options)) { if (key.includes('jpeg')) { const keyName = key.replace('jpeg_', '') jpegOptions[keyName] = value } } return await jpeg.encode(imageData, jpegOptions); case 'png': const pngOptions = {} for (const [key, value] of Object.entries(options)) { if (key.includes('png')) { const keyName = key.replace('png_', '') pngOptions[keyName] = value } } return await png.encode(imageData, pngOptions); //case 'webp': // return await webp.encode(imageData); default: throw new Error(`Unknown output type: ${outputType}`); } } async function convert(sourceType, outputType, fileBuffer) { const imageData = await decode(sourceType, fileBuffer); return encode(outputType, imageData); } function blobToBase64(blob) { return new Promise((resolve, _) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); } async function showOutput(imageBuffer, outputType) { const imageBlob = new Blob([imageBuffer], { type: `image/${outputType}` }); const base64String = await blobToBase64(imageBlob); return base64String; } async function handleUpload(attachment, isBulk = false, isSingle = false, target = null) { const attachmentData = attachment.attributes; const url = attachmentData?.originalImageURL ?? attachmentData.url; const mime = attachmentData.mime; const name = attachmentData.name; const filename = attachmentData?.originalImageName ?? attachmentData.filename; const attachmentID = attachmentData.id; const format = mime.split("/")[1]; const sourceType = format; const outputType = format; const options = JSON.parse(squeeze.options); let imageBuffer; let fileBuffer; let base64; if (format === "png") { const pngOptions = {} for (const [key, value] of Object.entries(options)) { if (key.includes('png')) { const keyName = key.replace('png_', '') pngOptions[keyName] = value } } imageBuffer = await fetch(url).then(res => res.arrayBuffer()).then(pngImageBuffer => optimise(pngImageBuffer, pngOptions)); base64 = await showOutput(imageBuffer, outputType); } else { let response = await fetch(url); let blob = await response.blob(); let metadata = { type: mime }; let imageObj = new File([blob], name, metadata); fileBuffer = await imageObj.arrayBuffer(); /* if (window.Worker) { //const myWorker = new Worker(new URL(`${squeeze.pluginUrl}/assets/js/worker.js`), { type: "module" }); const myWorker = new Worker(/* webpackChunkName: "foo-worker" */ /*new URL(`./worker.js`, import.meta.url)); myWorker.postMessage( { fileBuffer: fileBuffer, sourceType: sourceType, outputType: outputType, } ); console.log('Message posted to worker'); myWorker.onmessage = function(e) { console.log('Message received from worker', e.data); myWorker.terminate(); } } else { console.log('Your browser doesn\'t support web workers.'); } */ imageBuffer = await convert(sourceType, outputType, fileBuffer); base64 = await showOutput(imageBuffer, outputType); } let data = { action: 'squeeze_update_attachment', _ajax_nonce: squeeze.nonce, filename: filename, type: 'image', format: format, base64: base64, attachmentID: attachmentID, url: url, } jQuery.ajax({ url: squeeze.ajaxUrl, type: 'POST', data: data, beforeSend: function () { console.log('data', data) if (isBulk) bulkLogInput.value += `#${attachmentID}: ` + __('Compressed successfully, updating...', 'squeeze') + `\r\n`; }, error: function (error) { console.error(error) if (target) { target.closest("td").querySelector(".squeeze_status").innerText = __('An error has occured. Check the console for details.', 'squeeze') target.remove(); } }, success: function (response) { console.log(response) if (isBulk) { if (response.success) { bulkLogInput.value += `#${attachmentID}: ` + __('Updated successfully', 'squeeze') + `\r\n===============================\r\n`; handleBulkUpload() } else { bulkLogInput.value += `#${attachmentID}: ${response.data}\r\n===============================\r\n`; } } if (isSingle && target) { target.closest("td").querySelector(".squeeze_status").innerText = response.data; target.remove(); } if (!isSingle && !isBulk) { attachment.set('uploading', false) // resume uploading process } } }); } const handleBulkUpload = () => { const data = { action: 'squeeze_get_attachment', _ajax_nonce: squeeze.nonce, attachmentID: uncompressedIDs[0], } if (uncompressedIDs.length === 0) { alert(__('All images have been compressed!', 'squeeze')) bulkBtn.remove(); location.reload(); return; } bulkLogInput.value += `attachment #${uncompressedIDs[0]}: start compressing...\r\n`; jQuery.ajax({ url: squeeze.ajaxUrl, type: 'POST', data: data, error: function (error) { console.error(error) }, success: function (response) { //console.log(response) if (response.success) { const responseData = response.data; const attachment = { attributes: { url: responseData.url, mime: responseData.mime, name: responseData.name, filename: responseData.filename, id: responseData.id, } } //console.log(attachment, 'attachment') uncompressedIDs.shift(); handleUpload(attachment, true) } else { console.error(response.data) } } }); } function handleRestore(attachmentID, target) { let data = { action: 'squeeze_restore_attachment', _ajax_nonce: squeeze.nonce, attachmentID: attachmentID, } jQuery.ajax({ url: squeeze.ajaxUrl, type: 'POST', data: data, beforeSend: function () { target.disabled = true; target.innerText = __('Restore in process...', 'squeeze') }, error: function (error) { console.error(error) target.closest("td").querySelector(".squeeze_status").innerText = __('An error has occured. Check the console for details.', 'squeeze') target.remove(); }, success: function (response) { //console.log(response) target.closest("td").querySelector(".squeeze_status").innerText = response.data; //__('Restored successfully', 'squeeze') target.remove(); } }); } // Handle single compress button click const handleSingleBtnClick = (event) => { const attachmentID = event.target.dataset.attachment; wp?.media?.attachment(attachmentID).fetch().then(function (data) { const attachment = { attributes: data } handleUpload(attachment, false, true, event.target) }); } // Handle restore button click const handleRestoreBtnClick = (event) => { const attachmentID = event.target.dataset.attachment; handleRestore(attachmentID, event.target) } /** * Handle single buttons click */ function handleSingleButtonsClick() { document.addEventListener("click", (e) => { //console.log(e.target, 'e.target') const singleBtnName = 'squeeze_compress_single'; const restoreBtnName = 'squeeze_restore'; if (e.target.getAttribute("name") === singleBtnName) { e.target.disabled = true; e.target.innerText = __('Compressing...', 'squeeze') handleSingleBtnClick(e) } if (e.target.getAttribute("name") === restoreBtnName) { e.target.disabled = true; handleRestoreBtnClick(e) } }) } handleSingleButtonsClick() /** * Handle bulk button click */ bulkBtn?.addEventListener("click", (event) => { if (uncompressedIDs.length === 0) { return; } bulkBtn.disabled = true; handleBulkUpload() }) // https://wordpress.stackexchange.com/a/131295/186146 - override wp.Uploader.prototype.success jQuery.extend(wp?.Uploader?.prototype, { success: function (attachment) { //console.log(attachment, 'success'); const options = JSON.parse(squeeze.options); const isAutoCompress = options.auto_compress; let isImage = attachment.attributes.type === 'image' && (attachment.attributes.subtype === 'jpeg' || attachment.attributes.subtype === 'png') if (isImage && isAutoCompress) { // set 'uploading' param to true, to pause the uploading process attachment.set('uploading', true) handleUpload(attachment) } }, }); })(); //console.log(JSON.parse(squeeze.options), 'squeeze.options')