PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.5
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.5
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / media-optimization / assets / js / media-optimization-library.js

media-optimization-library.js in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.5, at media-optimization/assets/js/media-optimization-library.js

389 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Media Optimization Image Library Scripts
3 *
4 * @package Search Atlas SEO
5 * @copyright Copyright (C) 2021-2025, Search Atlas Group - support@searchatlas.com
6 * @since 2.6.0
7 *
8 * Localized data expected via metasyncMediaLib:
9 * - ajaxUrl: string
10 * - nonce: string
11 * - batchRunning: bool
12 * - i18n.optimizing: string
13 * - i18n.optimize: string
14 * - i18n.revert: string
15 * - i18n.revertConfirm: string
16 * - i18n.optimizeFailed:string
17 * - i18n.revertFailed: string
18 * - i18n.startBatch: string
19 * - i18n.batchFailed: string
20 * - i18n.batchComplete: string
21 * - i18n.imagesProcessed: string
22 * - i18n.failed: string
23 * - i18n.optimizingOf: string (e.g. "Optimizing")
24 * - i18n.of: string
25 * - i18n.images: string (e.g. "images...")
26 * - i18n.unoptimized: string
27 * - i18n.selectImages: string
28 * - i18n.bulkFailed: string
29 * - i18n.apply: string
30 */
31 (function() {
32 'use strict';
33
34 var config = window.metasyncMediaLib || {};
35 var nonce = config.nonce || '';
36 var ajaxUrl = config.ajaxUrl || window.ajaxurl;
37 var i18n = config.i18n || {};
38 var batchActive = false;
39 var fallbackPoll = null;
40
41 // ── Single Optimize ──
42 document.addEventListener('click', function(e) {
43 var btn = e.target.closest('.metasync-optimize-btn');
44 if (!btn) return;
45
46 var id = btn.dataset.id;
47 btn.classList.add('loading');
48 btn.disabled = true;
49 btn.innerHTML = '<span class="metasync-batch-spinner" style="width:14px;height:14px;display:inline-block;"></span> ' + (i18n.optimizing || 'Optimizing...');
50
51 fetch(ajaxUrl, {
52 method: 'POST',
53 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
54 body: 'action=metasync_optimize_single_image&nonce=' + nonce + '&attachment_id=' + id
55 })
56 .then(function(r) { return r.json(); })
57 .then(function(data) {
58 if (data.success) {
59 var row = btn.closest('tr');
60 var statusCell = row.querySelector('.column-status');
61 statusCell.innerHTML = data.data.status_html;
62
63 var actionsCell = row.querySelector('.column-actions');
64 actionsCell.innerHTML = '<button type="button" class="button button-small metasync-revert-btn" data-id="' + id + '">' +
65 '<span class="dashicons dashicons-undo" style="margin-top:3px;"></span> ' + (i18n.revert || 'Revert') + '</button>';
66
67 updateStats();
68 } else {
69 btn.classList.remove('loading');
70 btn.disabled = false;
71 btn.innerHTML = '<span class="dashicons dashicons-performance" style="margin-top:3px;"></span> ' + (i18n.optimize || 'Optimize');
72 alert(data.data || (i18n.optimizeFailed || 'Optimization failed.'));
73 }
74 })
75 .catch(function() {
76 btn.classList.remove('loading');
77 btn.disabled = false;
78 btn.innerHTML = '<span class="dashicons dashicons-performance" style="margin-top:3px;"></span> ' + (i18n.optimize || 'Optimize');
79 });
80 });
81
82 // ── Single Revert ──
83 document.addEventListener('click', function(e) {
84 var btn = e.target.closest('.metasync-revert-btn');
85 if (!btn) return;
86
87 if (!confirm(i18n.revertConfirm || 'Revert this image to its original format?')) {
88 return;
89 }
90
91 var id = btn.dataset.id;
92 btn.classList.add('loading');
93 btn.disabled = true;
94
95 fetch(ajaxUrl, {
96 method: 'POST',
97 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
98 body: 'action=metasync_revert_single_image&nonce=' + nonce + '&attachment_id=' + id
99 })
100 .then(function(r) { return r.json(); })
101 .then(function(data) {
102 if (data.success) {
103 var row = btn.closest('tr');
104 var statusCell = row.querySelector('.column-status');
105 statusCell.innerHTML = '<span class="metasync-status-badge metasync-status-unoptimized">' + (i18n.unoptimized || 'Unoptimized') + '</span>';
106
107 var actionsCell = row.querySelector('.column-actions');
108 actionsCell.innerHTML = '<button type="button" class="button button-small button-primary metasync-optimize-btn" data-id="' + id + '">' +
109 '<span class="dashicons dashicons-performance" style="margin-top:3px;"></span> ' + (i18n.optimize || 'Optimize') + '</button>';
110
111 updateStats();
112 } else {
113 btn.classList.remove('loading');
114 btn.disabled = false;
115 alert(data.data || (i18n.revertFailed || 'Revert failed.'));
116 }
117 })
118 .catch(function() {
119 btn.classList.remove('loading');
120 btn.disabled = false;
121 });
122 });
123
124 // ── Optimize All (Start Batch) ──
125 var optimizeAllBtn = document.getElementById('metasync-optimize-all');
126 if (optimizeAllBtn) {
127 optimizeAllBtn.addEventListener('click', function() {
128 if (!confirm(i18n.startBatch || 'Start optimizing all unoptimized images?')) {
129 return;
130 }
131
132 optimizeAllBtn.disabled = true;
133
134 fetch(ajaxUrl, {
135 method: 'POST',
136 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
137 body: 'action=metasync_start_batch_optimize&nonce=' + nonce
138 })
139 .then(function(r) { return r.json(); })
140 .then(function(data) {
141 if (data.success) {
142 showBatchProgress(data.data);
143 startBatchProcessing();
144 } else {
145 optimizeAllBtn.disabled = false;
146 alert(data.data || (i18n.batchFailed || 'Failed to start batch optimization.'));
147 }
148 })
149 .catch(function() {
150 optimizeAllBtn.disabled = false;
151 });
152 });
153 }
154
155 // ── Cancel Batch ──
156 var cancelBtn = document.getElementById('metasync-cancel-batch');
157 if (cancelBtn) {
158 cancelBtn.addEventListener('click', function() {
159 batchActive = false;
160 stopFallbackPoll();
161
162 fetch(ajaxUrl, {
163 method: 'POST',
164 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
165 body: 'action=metasync_cancel_batch_optimize&nonce=' + nonce
166 })
167 .then(function(r) { return r.json(); })
168 .then(function() {
169 document.getElementById('metasync-batch-progress').style.display = 'none';
170 if (optimizeAllBtn) optimizeAllBtn.disabled = false;
171 location.reload();
172 });
173 });
174 }
175
176 // ── Copy URL ──
177 document.addEventListener('click', function(e) {
178 var btn = e.target.closest('.metasync-copy-btn');
179 if (!btn) return;
180
181 var url = btn.dataset.url;
182 if (!url) return;
183
184 navigator.clipboard.writeText(url).then(function() {
185 btn.classList.add('copied');
186 var icon = btn.querySelector('.dashicons');
187 if (icon) {
188 icon.className = 'dashicons dashicons-yes';
189 setTimeout(function() {
190 icon.className = 'dashicons dashicons-clipboard';
191 btn.classList.remove('copied');
192 }, 1500);
193 }
194 });
195 });
196
197 // ── Dismiss Complete Notice ──
198 var dismissBtn = document.getElementById('metasync-dismiss-complete');
199 if (dismissBtn) {
200 dismissBtn.addEventListener('click', function() {
201 document.getElementById('metasync-batch-complete').style.display = 'none';
202 });
203 }
204
205 // ── AJAX-Driven Batch Processing ──
206
207 function startBatchProcessing() {
208 batchActive = true;
209 startFallbackPoll();
210 processNextBatch();
211 }
212
213 function processNextBatch() {
214 if (!batchActive) return;
215
216 fetch(ajaxUrl, {
217 method: 'POST',
218 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
219 body: 'action=metasync_process_batch_tick&nonce=' + nonce
220 })
221 .then(function(r) { return r.json(); })
222 .then(function(data) {
223 if (!data.success || !batchActive) return;
224
225 var progress = data.data;
226 showBatchProgress(progress);
227 applyStats(progress.stats);
228
229 if (progress.status === 'running') {
230 setTimeout(processNextBatch, 500);
231 } else {
232 onBatchFinished(progress);
233 }
234 })
235 .catch(function() {
236 if (batchActive) {
237 setTimeout(processNextBatch, 5000);
238 }
239 });
240 }
241
242 function onBatchFinished(progress) {
243 batchActive = false;
244 stopFallbackPoll();
245 document.getElementById('metasync-batch-progress').style.display = 'none';
246
247 if (progress.status === 'completed') {
248 var completeEl = document.getElementById('metasync-batch-complete');
249 var textEl = document.getElementById('metasync-batch-complete-text');
250 textEl.textContent = (i18n.batchComplete || 'Batch optimization complete!') + ' ' +
251 progress.processed + ' ' + (i18n.imagesProcessed || 'images processed') +
252 (progress.failed > 0 ? ', ' + progress.failed + ' ' + (i18n.failed || 'failed') : '') + '.';
253 completeEl.style.display = 'flex';
254 }
255
256 if (optimizeAllBtn) optimizeAllBtn.disabled = false;
257 setTimeout(function() { location.reload(); }, 1500);
258 }
259
260 function startFallbackPoll() {
261 if (fallbackPoll) return;
262 fallbackPoll = setInterval(function() {
263 fetch(ajaxUrl, {
264 method: 'POST',
265 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
266 body: 'action=metasync_batch_progress&nonce=' + nonce
267 })
268 .then(function(r) { return r.json(); })
269 .then(function(data) {
270 if (!data.success) return;
271 showBatchProgress(data.data);
272 applyStats(data.data.stats);
273 if (data.data.status !== 'running') {
274 onBatchFinished(data.data);
275 }
276 });
277 }, 10000);
278 }
279
280 function stopFallbackPoll() {
281 if (fallbackPoll) {
282 clearInterval(fallbackPoll);
283 fallbackPoll = null;
284 }
285 }
286
287 function showBatchProgress(progress) {
288 var el = document.getElementById('metasync-batch-progress');
289 el.style.display = '';
290
291 var pct = progress.total > 0 ? Math.round((progress.processed / progress.total) * 100) : 0;
292 document.getElementById('metasync-batch-fill').style.width = pct + '%';
293 document.getElementById('metasync-batch-text').textContent =
294 (i18n.optimizingOf || 'Optimizing') + ' ' + progress.processed + ' ' + (i18n.of || 'of') + ' ' + progress.total + ' ' + (i18n.images || 'images...');
295 document.getElementById('metasync-batch-processed').textContent = progress.processed;
296 document.getElementById('metasync-batch-total').textContent = progress.total;
297 }
298
299 function applyStats(stats) {
300 if (!stats) return;
301 var statNumbers = document.querySelectorAll('.metasync-stat-number');
302 if (statNumbers.length >= 3) {
303 statNumbers[0].textContent = stats.total;
304 statNumbers[1].textContent = stats.optimized;
305 statNumbers[2].textContent = stats.unoptimized;
306 }
307 var pctEl = document.querySelector('.metasync-stat-percentage');
308 if (pctEl) pctEl.textContent = stats.percentage + '%';
309 var fillEl = document.querySelector('.metasync-stat-progress-fill');
310 if (fillEl) fillEl.style.width = stats.percentage + '%';
311 }
312
313 function updateStats() {
314 fetch(ajaxUrl, {
315 method: 'POST',
316 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
317 body: 'action=metasync_batch_progress&nonce=' + nonce
318 })
319 .then(function(r) { return r.json(); })
320 .then(function(data) {
321 if (data.success) applyStats(data.data.stats);
322 });
323 }
324
325 // Auto-resume AJAX chain if batch is already running (e.g. page reload)
326 if (config.batchRunning) {
327 startBatchProcessing();
328 }
329
330 // ── Bulk Optimize Selected ──
331 var bulkForm = document.getElementById('metasync-image-library-form');
332 if (bulkForm) {
333 bulkForm.querySelectorAll('input[type="submit"], button[type="submit"]').forEach(function(btn) {
334 btn.addEventListener('click', function() {
335 bulkForm._lastSubmitter = btn;
336 });
337 });
338
339 bulkForm.addEventListener('submit', function(e) {
340 var submitter = e.submitter || bulkForm._lastSubmitter;
341 var applyBtnTop = bulkForm.querySelector('#doaction');
342 var applyBtnBottom = bulkForm.querySelector('#doaction2');
343
344 var isTopApply = submitter && submitter === applyBtnTop;
345 var isBottomApply = submitter && submitter === applyBtnBottom;
346 if (!isTopApply && !isBottomApply) return;
347
348 var actionName = isTopApply ? 'action' : 'action2';
349 var action = bulkForm.querySelector('[name="' + actionName + '"]');
350 if (!action || action.value !== 'bulk_optimize') return;
351
352 e.preventDefault();
353
354 var checked = bulkForm.querySelectorAll('input[name="image_ids[]"]:checked');
355 if (checked.length === 0) {
356 alert(i18n.selectImages || 'Please select at least one image.');
357 return;
358 }
359
360 var ids = [];
361 checked.forEach(function(cb) { ids.push(cb.value); });
362
363 var clickedBtn = isTopApply ? applyBtnTop : applyBtnBottom;
364 clickedBtn.disabled = true;
365 clickedBtn.value = i18n.optimizing || 'Optimizing...';
366
367 fetch(ajaxUrl, {
368 method: 'POST',
369 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
370 body: 'action=metasync_bulk_optimize_selected&nonce=' + nonce + '&ids=' + ids.join(',')
371 })
372 .then(function(r) { return r.json(); })
373 .then(function(data) {
374 if (data.success) {
375 location.reload();
376 } else {
377 clickedBtn.disabled = false;
378 clickedBtn.value = i18n.apply || 'Apply';
379 alert(data.data || (i18n.bulkFailed || 'Bulk optimization failed.'));
380 }
381 })
382 .catch(function() {
383 clickedBtn.disabled = false;
384 clickedBtn.value = i18n.apply || 'Apply';
385 });
386 });
387 }
388 })();
389