PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / js / wpoadmin.js

wpoadmin.js in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at js/wpoadmin.js

2,798 lines 86.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(function ($) {
2 WP_Optimize = WP_Optimize();
3 if ('undefined' != typeof WP_Optimize_Cache) WP_Optimize_Cache = WP_Optimize_Cache();
4 if ('undefined' != typeof wp_optimize.minify) WP_Optimize_Minify = wp_optimize.minify.init();
5 });
6
7 (function($) {
8 /*
9 * Form errors store
10 */
11 var errors = [];
12 $.fn.form_errors = function() {
13 return this;
14 }
15 $.fn.form_errors.add = function(type, message) {
16 if (false !== this.has_error((type))) return;
17 errors.push({type: type, message: message});
18 };
19 $.fn.form_errors.remove = function(type) {
20 var found_error = this.has_error(type);
21 if (found_error !== false) {
22 errors.splice(found_error, 1);
23 }
24 };
25 $.fn.form_errors.has_error = function(type) {
26 var has_error = false;
27 $.each(errors, function(index, error) {
28 console.log(index, error)
29 if (type == error.type) {
30 has_error = index;
31 }
32 }.bind(this));
33 return has_error;
34 };
35 $.fn.form_errors.has_errors = function() {
36 return errors.length > 0;
37 }
38 })(jQuery);
39
40 /**
41 * Main WP_Optimize - Function for sending communications.
42 */
43 var WP_Optimize = function () {
44 var $ = jQuery;
45 var debug_level = 0;
46 var queue = new Updraft_Queue();
47 var block_ui = wp_optimize.block_ui;
48 var send_command = wp_optimize.send_command;
49 var optimization_force = false;
50 var optimization_logged_warnings = false;
51 var force_single_table_optimization = false;
52 var heartbeat = WP_Optimize_Heartbeat();
53
54 // Dashboard refresh button
55 $(document).on('click', '#wpo-dashboard-refresh', function(e) {
56 e.preventDefault();
57 var $btn = $(this);
58 var $icon = $btn.find('.dashicons');
59 $btn.prop('disabled', true);
60 $icon.addClass('wpo-spinning');
61 send_command('refresh_dashboard', {}, function(resp) {
62 if (resp && resp.success) {
63 if (resp.top_row) {
64 $('.wpo-top-row').html(resp.top_row);
65 }
66 if (resp.mod_grid) {
67 $('.wpo-mod-grid').html(resp.mod_grid);
68 }
69 }
70 }).fail(function() {
71 block_ui(wpoptimize.something_wrong_try_again, {}, 3000);
72 }).always(function() {
73 $btn.prop('disabled', false);
74 $icon.removeClass('wpo-spinning');
75 });
76 });
77
78 /*
79 * Enable select all checkbox for optimizations list.
80 */
81 define_select_all_checkbox($('#select_all_optimizations'), $('#optimizations_list .optimization_checkbox'));
82
83 /**
84 * Either display normally, or grey-out, the scheduling options, depending on whether any schedule has been selected.
85 *
86 * @return {string}
87 */
88 function enable_or_disable_schedule_options() {
89 if ($('#enable-schedule').length) {
90 var schedule_enabled = $('#enable-schedule').is(':checked');
91 if (schedule_enabled) {
92 $('#wp-optimize-auto-options').css('opacity', '1');
93 } else {
94 $('#wp-optimize-auto-options').css('opacity', '0.5')
95 }
96 }
97 }
98
99 enable_or_disable_schedule_options();
100
101 $('#enable-schedule').on('change', function () {
102 enable_or_disable_schedule_options();
103 });
104
105 /*
106 * Triggered when the database tabs are loaded.
107 */
108
109 $(document).on('wpo_database_tabs_loaded', function() {
110 /*
111 * Setup table events and tablesorter
112 */
113
114 var elTable = document.getElementById('wpoptimize_table_list');
115
116 if (null === elTable) return;
117
118 enhanceSortableAccessibility([elTable]);
119
120 document.getElementById('wpoptimize_table_list_filter').addEventListener('input', function () {
121 var filter = this.value.toLowerCase();
122 var regex = new RegExp(filter, 'i');
123 var tbody = elTable.querySelector('tbody');
124 var tfoot = elTable.querySelector('tfoot');
125 var rows = tbody.getElementsByTagName('tr');
126 var hidden = 0;
127
128 for (var i = 0; i < rows.length; i++) {
129 var cell = rows[i].getElementsByTagName('td')[1];
130 if (cell) {
131 var value = cell.getAttribute('data-tablename');
132 if (regex.test(value)) {
133 rows[i].style.display = "";
134 } else {
135 rows[i].style.display = "none";
136 hidden++;
137 }
138 }
139 }
140
141 if (tfoot) tfoot.style.display = hidden > 0 ? "none" : "";
142
143 var tables_not_found = document.getElementById('wpoptimize_table_list_tables_not_found');
144
145 // Check if rows are visible
146 if (hidden === rows.length) {
147 tables_not_found.style.display = 'block';
148 } else {
149 tables_not_found.style.display = 'none';
150 }
151
152 });
153
154 /*
155 * Setup force optimization checkboxes and associated events
156 */
157
158 var optimization_force_checkbox = $('#innodb_force_optimize');
159 var optimization_row = optimization_force_checkbox.closest('tr');
160 var single_table_optimization_force = $('#innodb_force_optimize_single');
161
162 optimization_force_checkbox.on('change', function() {
163 $('button, input[type="checkbox"]', optimization_row).each(function() {
164 optimization_force = optimization_force_checkbox.is(':checked');
165 var btn = $(this);
166 if (btn.data('disabled')) {
167 if (optimization_force) {
168 btn.prop('disabled', false);
169 } else {
170 btn.prop('disabled', true);
171 }
172 }
173 });
174 });
175
176 // Handle force optimization checkbox on table list tab.
177 single_table_optimization_force.on('change', function() {
178 force_single_table_optimization = $(this).is(':checked');
179 update_single_table_optimization_buttons(force_single_table_optimization);
180 });
181
182 // Set initial value
183 force_single_table_optimization = single_table_optimization_force.is(':checked');
184 optimization_force = optimization_force_checkbox.is(':checked');
185
186 // Update single table optimization buttons state on load.
187 update_single_table_optimization_buttons(force_single_table_optimization);
188
189 // Attach warning events
190 add_warning_for_delete_post_meta_action();
191 add_warning_for_delete_orphaned_relationship_data_action();
192
193 });
194
195 /**
196 * Temporarily show a dashboard notice, and then remove it. The HTML will be prepended to the .wrap.wp-optimize-wrap element.
197 *
198 * @param {String} html_contents HTML to display.
199 * @param {String} where CSS selector of where to prepend the HTML to.
200 * @param {Number} [delay=15] The number of seconds to wait before removing the message.
201 *
202 * @return {string}
203 */
204 function temporarily_display_notice(html_contents, where, delay) {
205 where = ('undefined' === typeof where) ? '#wp-optimize-wrap' : where;
206 delay = ('undefined' === typeof delay) ? 15 : delay;
207 $(html_contents).hide().prependTo(where).slideDown('fast').delay(delay * 1000).slideUp('fast', function () {
208 $(this).remove();
209 });
210 }
211
212 /**
213 * Send a request to disable or enable comments or trackbacks
214 *
215 * @param {string} type - either "comments" or "trackbacks"
216 * @param {boolean} enable - whether to enable, or, to disable
217 *
218 * @return {string}
219 */
220 function enable_or_disable_feature(type, enable) {
221 var data = {
222 type: type,
223 enable: enable ? 1 : 0
224 };
225
226 $('#' + type + '_spinner').show();
227
228 send_command('enable_or_disable_feature', data, function (resp) {
229 $('#' + type + '_spinner').hide();
230
231 if (resp && resp.hasOwnProperty('output')) {
232 for (var i = 0, len = resp.output.length; i < len; i++) {
233 var new_html = '<div class="updated"><p>' + resp.output[i] + '</p></div>';
234 temporarily_display_notice(new_html, '#' + type + '_notice');
235 }
236 }
237 if (resp && resp.hasOwnProperty('messages')) {
238 $('#' + type + '_actionmsg').html(resp.messages.join(' - '));
239 }
240 });
241 }
242
243 $('#wp-optimize-disable-enable-trackbacks-enable').on('click', function () {
244 enable_or_disable_feature('trackbacks', true);
245 });
246
247 $('#wp-optimize-disable-enable-trackbacks-disable').on('click', function () {
248 enable_or_disable_feature('trackbacks', false);
249 });
250
251 $('#wp-optimize-disable-enable-comments-enable').on('click', function () {
252 enable_or_disable_feature('comments', true);
253 });
254
255 $('#wp-optimize-disable-enable-comments-disable').on('click', function () {
256 enable_or_disable_feature('comments', false);
257 });
258
259 // Main menu
260 $('.wpo-pages-menu').on('click', 'a', function(e) {
261 e.preventDefault();
262 if (!$(this).is('.active')) {
263 $('.wpo-pages-menu a.active').removeClass('active');
264 $('.wpo-page.active').removeClass('active');
265 $(this).addClass('active');
266 $('.wpo-page[data-whichpage="' + $(this).data('menuslug') + '"]').addClass('active');
267 window.scroll(0, 0);
268
269 // Trigger a global event when changing page
270 $('#wp-optimize-wrap').trigger('page-change', { page: $(this).data('menuslug') });
271 }
272
273 // Close the menu on mobile
274 $('#wp-optimize-nav-page-menu').trigger('click');
275
276 });
277
278 $('#wp-optimize-wrap').on('page-change', function(e, params) {
279 // Trigger the global tab change events when changing page
280 var active_tab = $('.wpo-page[data-whichpage='+params.page+']').find('.nav-tab-wrapper .nav-tab-active');
281 $('#wp-optimize-wrap').trigger('tab-change', { page: params.page, tab: active_tab.data('tab') });
282 $('#wp-optimize-wrap').trigger('tab-change/'+params.page+'/'+active_tab.data('tab'), { content: $('#' + active_tab.attr('id') + '-contents')});
283
284 maybe_show_too_many_tables_popup(active_tab.attr('data-tab'));
285 });
286
287 // set a time out, as needs to be done once the rest is loaded
288 setTimeout(function() {
289 // Trigger page-change event on load
290 $('#wp-optimize-wrap').trigger('page-change', { page: $('.wpo-pages-menu a.active').data('menuslug') });
291 }, 500);
292
293 // Tabs menu
294 $('.nav-tab-wrapper .nav-tab').on('click', function (e) {
295 e.preventDefault();
296
297 var clicked_tab_id = $(this).attr('id'),
298 container = $(this).closest('.nav-tab-wrapper');
299
300 if (!clicked_tab_id) { return; }
301
302 toggle_mobile_menu(false);
303 // Mobile menu TABS toggle
304 if ($(this).is('[id^="wp-optimize-nav-tab-menu-"]')) {
305 toggle_mobile_menu(true);
306 return;
307 }
308
309 container.find('.nav-tab:not(#wp-optimize-nav-tab-' + clicked_tab_id + ')').removeClass('nav-tab-active');
310
311 $(this).addClass('nav-tab-active');
312 $(this).closest('.wpo-page').find('.wp-optimize-nav-tab-contents').hide();
313 $('#' + clicked_tab_id + '-contents').show();
314
315 // Trigger global events on tab change
316 $('#wp-optimize-wrap').trigger('tab-change', { page: $(this).data('page'), tab: $(this).data('tab') });
317 $('#wp-optimize-wrap').trigger('tab-change/'+$(this).data('page')+'/'+$(this).data('tab'), { content: $('#' + clicked_tab_id + '-contents')});
318
319 });
320
321 // Mobile menu toggle
322 $('#wp-optimize-nav-page-menu').on('click', function(e) {
323 e.preventDefault();
324 $(this).toggleClass('opened');
325 });
326
327 /*
328 * Setup a simple cross-pages/tabs navigation.
329 *
330 * Basic example: <button class="js--wpo-goto" data-page="wpo_minify" data-tab="status">Go to the minify page, status tab</button>
331 */
332 $('#wp-optimize-wrap').on('click', '.js--wpo-goto', function(e) {
333 e.preventDefault();
334 // get the page and tab
335 var page = $(this).data('page');
336 var tab = $(this).data('tab');
337 if (page) {
338 // Trigger a page change
339 $('.wpo-pages-menu a[data-menuslug="' + page + '"]').trigger('click');
340 }
341 if (tab) {
342 // Change tab change
343 $('.wpo-page.active .nav-tab-wrapper a[data-tab="' + tab + '"]').trigger('click');
344 }
345 });
346
347 /**
348 * Toggle Mobile menu
349 *
350 * @param {bool} open
351 *
352 * @return {void}
353 */
354 function toggle_mobile_menu(open) {
355 if (open) {
356 $('#wp-optimize-wrap').addClass('wpo-mobile-menu-opened');
357 } else {
358 $('#wp-optimize-wrap').removeClass('wpo-mobile-menu-opened');
359 }
360 }
361
362 var database_tabs_loading = false;
363 var database_tabs_loaded = false;
364 // When showing the tables tab
365 $('#wp-optimize-wrap').on('tab-change/wpo_database/tables', function(e) {
366 get_database_tabs();
367 });
368
369 // When showing the optimizations tab
370 $('#wp-optimize-wrap').on('tab-change/wpo_database/optimize', function(event, data) {
371 get_database_tabs();
372 });
373
374
375 // When showing the settings tab
376 $('#wp-optimize-wrap').on('tab-change/wpo_settings/settings', function(event, data) {
377 // If the innodb_force_optimize--container is present, fetch the required data.
378 // We load the database tabs together, as they need the same processing.
379 if (data.content.find('.innodb_force_optimize--container').length) get_database_tabs();
380 WPO_Status_Report();
381 });
382
383 /**
384 * Get the data for the database tabs. We get them at the same time, as they both need the same time consuming requests.
385 */
386 function get_database_tabs() {
387 if (database_tabs_loading || database_tabs_loaded) return;
388 var container = $('.wpo-page[data-whichpage=wpo_database]');
389 var shade = container.find('.wpo_shade');
390 shade.removeClass('hidden');
391 database_tabs_loading = true;
392 send_command('get_database_tabs', {}, function(response) {
393 // Set the status to true, to prevent loading again.
394 database_tabs_loaded = true;
395
396 // Update the optimizations tab
397 if (response.hasOwnProperty('optimizations')) {
398 container.find('.wp-optimize-optimizations-table-placeholder').replaceWith(response.optimizations);
399 }
400
401 // If the batch table scan hasn't finished yet, trigger the loading popup so it
402 // runs automatically. The popup will reload the page once the scan completes.
403 if (true === response.scan_pending) {
404 // Add a scan-first notice beneath the disabled "Optimize database tables" info.
405 var $optimizeDbInfo = $('#optimization_info_optimizetables');
406 if ($optimizeDbInfo.length) {
407 $optimizeDbInfo.append(
408 '<br><span class="wpo-scan-pending-notice">' +
409 wpoptimize.db_tables_scan_pending_optimize + ' ' +
410 '<a href="#" id="wpo-optimizations-tab-scan-link">' + wpoptimize.db_tables_scan_button + '</a>' +
411 '</span>'
412 );
413 $('#wpo-optimizations-tab-scan-link').on('click', function(e) {
414 e.preventDefault();
415 var scanBtn = document.getElementById('wpo-load-tables-in-batches');
416 if (scanBtn) scanBtn.click();
417 });
418 }
419
420 // Replace the spinner placeholder in the tables tab with a scan-first notice.
421 $('#wpoptimize_table_list tbody').html(
422 '<tr>' +
423 '<td></td>' +
424 '<td colspan="6" style="text-align:center;padding:1em;">' +
425 wpoptimize.db_tables_scan_pending_list + ' ' +
426 '<a href="#" id="wpo-tables-tab-scan-link">' + wpoptimize.db_tables_scan_button + '</a>' +
427 '</td>' +
428 '<td></td>' +
429 '</tr>'
430 );
431 $('#wpo-tables-tab-scan-link').on('click', function(e) {
432 e.preventDefault();
433 var scanBtn = document.getElementById('wpo-load-tables-in-batches');
434 if (scanBtn) scanBtn.click();
435 });
436
437 var scanBtn = document.getElementById('wpo-load-tables-in-batches');
438 if (scanBtn) {
439 // If the onboarding wizard modal is currently open in the DOM, wait for it
440 // to close before auto-clicking — otherwise the thickbox would stack on top.
441 var onboardingRoot = document.getElementById('onboarding-modal-root');
442 if (onboardingRoot && onboardingRoot.querySelector('[data-state="open"]')) {
443 var scanObserver = new MutationObserver(function(mutations, obs) {
444 if (!onboardingRoot.querySelector('[data-state="open"]')) {
445 obs.disconnect();
446 scanBtn.click();
447 }
448 });
449 scanObserver.observe(onboardingRoot, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-state'] });
450 } else {
451 scanBtn.click();
452 }
453 }
454 } else {
455 // Update the optimizations tables list
456 update_tables_list(response);
457 }
458
459 $(document).trigger('wpo_database_tabs_loaded');
460
461 }).always(function() {
462 database_tabs_loading = false;
463 shade.addClass('hidden');
464 });
465 }
466
467 /**
468 * Gathers the settings from the settings tab and return in selected format.
469 *
470 * @param {string} output_format optional param 'object' or 'string'.
471 *
472 * @return (string) - serialized settings.
473 */
474 function gather_settings(output_format) {
475 var form_data = '',
476 output_format = ('undefined' === typeof output_format) ? 'string' : output_format,
477 $form_elements = $("#wp-optimize-database-settings form input[name!='action'], #wp-optimize-database-settings form select, #wp-optimize-database-settings form textarea, #wp-optimize-general-settings form input[name!='action'], #wp-optimize-general-settings form textarea, #wp-optimize-general-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-'], #wpo-404-detector-form input[type=checkbox]");
478
479 if ('object' == output_format) {
480 form_data = $form_elements.serializeJSON({useIntKeysAsArrayIndex: true});
481 } else {
482 // Excluding the unnecessary 'action' input avoids triggering a very misconceived mod_security rule seen on one user's site.
483 form_data = $form_elements.serialize();
484
485 // Include unchecked checkboxes. user filter to only include unchecked boxes.
486 $.each($('#wp-optimize-database-settings form input[type=checkbox], #wp-optimize-general-settings form input[type=checkbox], .wp-optimize-nav-tab-contents input[name^="enable-auto-backup-"], #wpo-404-detector-form input[type=checkbox]')
487 .filter(function (idx) {
488 return $(this).prop('checked') == false
489 }),
490 function (idx, el) {
491 // Attach matched element names to the form_data with chosen value.
492 var empty_val = '0';
493 form_data += '&' + $(el).attr('name') + '=' + empty_val;
494 }
495 );
496 }
497
498 return form_data;
499 }
500
501 /**
502 * Runs after all queued commands done and sends optimizations_done command
503 *
504 * @return {string}
505 */
506 function process_done() {
507 send_command('optimizations_done', {}, function () {});
508 // Reset the warning flag
509 optimization_logged_warnings = false;
510 }
511
512 /**
513 * Processes the queue
514 *
515 * @return void
516 */
517 function process_queue() {
518 if (!queue.get_lock()) {
519 if (debug_level > 0) {
520 console.log("WP-Optimize: process_queue(): queue is currently locked - exiting");
521 }
522 return;
523 }
524
525 if (debug_level > 0) {
526 console.log("WP-Optimize: process_queue(): got queue lock");
527 }
528
529 var id = queue.peek();
530 var blog_id = 0;
531 var sites_container = $("#wpo_all_sites");
532 var active_site = sites_container.data('active_site');
533
534 // Check to see if an object has been returned.
535 if (typeof id == 'object') {
536 data = id;
537 id = id.optimization_id;
538 blog_id = data.blog_id;
539
540 if ("undefined" == typeof active_site) {
541 sites_container.data('active_site', blog_id);
542 do_site_ui_update(blog_id, 0);
543 } else if (active_site != blog_id) {
544 var prev_blog_id = active_site;
545 sites_container.data('active_site', blog_id);
546 do_site_ui_update(blog_id, prev_blog_id);
547 }
548
549 } else {
550 data = {};
551 }
552
553 if ('undefined' === typeof id) {
554 if (debug_level > 0) console.log("WP-Optimize: process_queue(): queue is apparently empty - exiting");
555 queue.unlock();
556 var prev_blog_id = sites_container.data('active_site');
557 do_site_ui_update(0, prev_blog_id);
558 process_done();
559 return;
560 }
561
562 if (debug_level > 0) console.log("WP-Optimize: process_queue(): processing item: " + id);
563
564 queue.dequeue();
565
566 $(document).trigger(['do_optimization_', id, '_start'].join(''));
567
568 if ('optimizetables' === id) {
569 // Display the table name being optimized
570 $('#optimization_info_' + id).html(wpoptimize.optimizing_table + ' ' + data.optimization_table);
571
572 // Set extra options for the request
573 var timeout = parseInt(wpoptimize.table_optimization_timeout) ? parseInt(wpoptimize.table_optimization_timeout) : 120000;
574 var request_options = {
575 timeout: timeout,
576 error: function(error, type) {
577 optimization_logged_warnings = true;
578 if ('timeout' === type) {
579 console.warn('The request to optimize the table ' + data.optimization_table + ' timed out after ' + (timeout / 1000) + ' seconds');
580 } else {
581 console.warn('There was an error when running the optimization "' + id + '".', type, error, data);
582 }
583 if (queue.is_empty()) {
584 var blog_id = sites_container.data('active_site');
585 do_site_ui_update(blog_id, 0);
586 $('#optimization_spinner_' + id).hide();
587 $('#optimization_checkbox_' + id).show();
588 $('.optimization_button_' + id).prop('disabled', false);
589 $('#optimization_info_' + id).html(wpoptimize.optimization_complete + ' ' + wpoptimize.with_warnings);
590 }
591
592 setTimeout(function () {
593 queue.unlock(); process_queue();
594 }, 500);
595 }
596 }
597 } else {
598 var request_options = {};
599 }
600
601 send_command('do_optimization', { optimization_id: id, data: data }, function (response) {
602 $('#optimization_spinner_' + id).hide();
603 $('#optimization_checkbox_' + id).show();
604 $('.optimization_button_' + id).prop('disabled', false);
605
606 $(document).trigger(['do_optimization_', id, '_done'].join(''), response);
607
608 if (response) {
609 var total_output = '';
610 for (var i = 0, len = response.errors.length; i < len; i++) {
611 total_output += '<span class="error">' + response.errors[i] + '</span><br>';
612 }
613 for (var i = 0, len = response.messages.length; i < len; i++) {
614 total_output += response.errors[i] + '<br>';
615 }
616 for (var i = 0, len = response.result.output.length; i < len; i++) {
617 total_output += response.result.output[i] + '<br>';
618 }
619 $('#optimization_info_' + id).html(total_output);
620 if (response.hasOwnProperty('status_box_contents')) {
621 $('#wp_optimize_status_box').css('opacity', '1').find('.inside').html(response.status_box_contents);
622 }
623 if (response.hasOwnProperty('table_list')) {
624 $('#wpoptimize_table_list tbody').html($(response.table_list).find('tbody').html());
625 }
626 if (response.hasOwnProperty('total_size')) {
627 $('#optimize_current_db_size').html(response.total_size);
628 }
629
630 if ('optimizetables' === id) {
631 // Status check for optimizing tables.
632 const optimizetables_id = "optimizetables";
633 if (queue.contains_id(optimizetables_id)) {
634 $('#optimization_checkbox_' + optimizetables_id).hide();
635 $('#optimization_spinner_' + optimizetables_id).show();
636 $('.optimization_button_' + optimizetables_id).prop('disabled', true);
637 } else {
638 $('#optimization_checkbox_' + optimizetables_id).show();
639 $('#optimization_spinner_' + optimizetables_id).hide();
640 $('.optimization_button_' + optimizetables_id).prop('disabled', false);
641 $('#optimization_info_' + optimizetables_id).html(wpoptimize.optimization_complete + (optimization_logged_warnings ? (' ' + wpoptimize.with_warnings) : ''));
642 }
643 }
644
645 // check if we need update unapproved comments count.
646 if (response.result.meta && response.result.meta.hasOwnProperty('awaiting_mod')) {
647 var awaiting_mod = response.result.meta.awaiting_mod;
648 if (awaiting_mod > 0) {
649 $('#adminmenu .awaiting-mod .pending-count').remove(awaiting_mod);
650 } else {
651 // if there is no unapproved comments then remove bullet.
652 $('#adminmenu .awaiting-mod').remove();
653 }
654 }
655 }
656 setTimeout(function () {
657 queue.unlock(); process_queue();
658 }, 500);
659 }, true, request_options);
660 }
661
662 /**
663 * Update UI of sites list based on which site is currently being optimizated
664 *
665 * @param {Number} blog_id - current site id being optimized
666 * @param {Number} prev_blog_id - previous site id
667 *
668 * @return void
669 */
670 function do_site_ui_update(blog_id, prev_blog_id) {
671 if (0 != prev_blog_id) {
672 $("#site-" + prev_blog_id).show();
673 $("#optimization_spinner_site-" + prev_blog_id).hide();
674 }
675 $("#site-" + blog_id).hide();
676 $("#optimization_spinner_site-" + blog_id).show();
677 }
678
679 /**
680 * Runs a specified optimization, displaying the progress and results in the optimization's row
681 *
682 * @param {string} id - The optimization ID
683 *
684 * @return void
685 */
686 function do_optimization(id) {
687 var $optimization_row = $('#wp-optimize-nav-tab-contents-optimize .wp-optimize-settings-' + id);
688
689 if (!$optimization_row) {
690 console.log("do_optimization: row corresponding to this optimization (" + id + ") not found");
691 }
692
693 // check if there any additional inputs checkboxes.
694 var additional_data = {},
695 additional_data_length = 0;
696
697 $('input[type="checkbox"]', $('#optimization_info_' + id)).each(function() {
698 var checkbox = $(this);
699
700 if (checkbox.is(':checked')) {
701 additional_data[checkbox.attr('name')] = checkbox.val();
702 additional_data_length++;
703 }
704 });
705
706 // don't run optimization if optimization active.
707 if (true == $('.optimization_button_' + id).prop('disabled')) return;
708
709 var no_queue_actions_added = false;
710
711 // Check if it is DB optimize.
712 if ('optimizetables' == id) {
713 var optimization_tables = $('#wpoptimize_table_list #the-list tr'),
714 filter_by_blog_id = $('#wpo_sitelist_moreoptions').length > 0 && $('#wpo_sitelist_moreoptions').is(':visible'),
715 selected_sites = [];
716
717 // Get list of selected sites.
718 if (filter_by_blog_id) {
719 selected_sites = $('#wpo_sitelist_moreoptions input[type="checkbox"]:checked').map(function() {
720 return parseInt($(this).val());
721 }).get();
722 }
723
724 no_queue_actions_added = true;
725
726 // Check if there are any tables to be optimized.
727 $(optimization_tables).each(function (index) {
728 // Get information from each td.
729 var $table_information = $(this).find('td');
730
731 // Get table type information.
732 var table_type = $(this).data('type');
733 var table = $(this).data('tablename');
734 var optimizable = $(this).data('optimizable');
735 var blog_id = $(this).data('blog_id') ? parseInt($(this).data('blog_id')) : 1;
736 var in_selected_sites = true;
737
738
739 // Check if table is in the list of selected sites (multisite mode).
740 if (filter_by_blog_id && -1 == selected_sites.indexOf(blog_id)) {
741 in_selected_sites = false;
742 }
743
744 // Make sure the table isnt blank.
745 if ('' != table && in_selected_sites) {
746 // Check if table is optimizable or optimization forced by user.
747 if (1 == parseInt(optimizable) || optimization_force) {
748 var data = {
749 optimization_id: id,
750 blog_id: blog_id,
751 optimization_table: table,
752 optimization_table_type: table_type,
753 optimization_force: optimization_force
754 };
755
756 queue.enqueue(data);
757
758 no_queue_actions_added = false;
759 }
760 }
761 });
762 } else {
763 // check if additional data passed for optimization.
764 data = {
765 optimization_id: id
766 };
767
768 if (additional_data_length > 0) {
769 for (var i in additional_data) {
770 if (!additional_data.hasOwnProperty(i)) continue;
771 data[i] = additional_data[i];
772 }
773 }
774
775 queue.enqueue(data);
776 }
777
778 // if new actions was not added in tasks queue then we don't process queue.
779 if (no_queue_actions_added) return;
780
781 $('#optimization_checkbox_' + id).hide();
782 $('#optimization_spinner_' + id).show();
783 $('.optimization_button_' + id).prop('disabled', true);
784
785 $('#optimization_info_' + id).html('...');
786
787 process_queue();
788 }
789
790
791 /**
792 * Run action and save selected sites list options.
793 *
794 * @param {function} action - action to do after save.
795 *
796 * @return void
797 */
798 function save_sites_list_and_do_action(action) {
799 // if multisite mode then save sites list before action.
800 if ($('#wpo_settings_sites_list').length) {
801 // save wpo-sites settings.
802 send_command('save_site_settings', {'wpo-sites': get_selected_sites_list()}, function () {
803 // do action.
804 if (action) action();
805 });
806 } else {
807 // do action.
808 if (action) action();
809 }
810 }
811
812 /**
813 * Returns list of selected sites list.
814 *
815 * @return {Array}
816 */
817 function get_selected_sites_list() {
818 var wpo_sites = [];
819
820 $('#wpo_settings_sites_list input[type="checkbox"]').each(function () {
821 var checkbox = $(this);
822 if (checkbox.is(':checked')) {
823 wpo_sites.push(checkbox.attr('value'));
824 }
825 });
826
827 return wpo_sites;
828 }
829
830 /*
831 * Run single optimization click.
832 */
833 $('#wp-optimize-nav-tab-wpo_database-optimize-contents').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
834 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
835 if (!optimization_id) {
836 console.log("Optimization ID corresponding to pressed button not found");
837 return;
838 }
839 // if run button disabled then don't run this optimization.
840 if (true == $('.optimization_button_' + optimization_id).prop('disabled')) return;
841 // disable run button before save sites list.
842 $('.optimization_button_' + optimization_id).prop('disabled', true);
843
844 save_sites_list_and_do_action(function() {
845 $('.optimization_button_' + optimization_id).prop('disabled', false);
846 do_optimization(optimization_id);
847 });
848 });
849
850 /*
851 * Run all optimizations click.
852 */
853 $('#wp-optimize-nav-tab-wpo_database-optimize-contents #wp-optimize').on('click', function (e) {
854 e.preventDefault();
855
856 if (null == tmpl_wpo_grouped_warnings_tpl) {
857 tmpl_wpo_grouped_warnings_tpl = $('#tmpl-wpo-grouped-warnings').html().toString();
858 }
859
860 user_confirm_destructive_actions(function() {
861 return function(run_btn) {
862 // disable run button to avoid double click.
863 $(run_btn).prop('disabled', true);
864 save_sites_list_and_do_action(function() {
865 $(run_btn).prop('disabled', false);
866 run_optimizations();
867 });
868 };
869 }(this));
870 });
871
872 var tmpl_wpo_grouped_warnings_tpl = null;
873
874 /**
875 * Prepare the stack of optimizations that the user will need to actively confirm using the popup
876 * Then show them in sequence
877 */
878 function user_confirm_destructive_actions(callback) {
879 var optimizations = $('#optimizations_list .optimization_checkbox:checked');
880
881 var confirmations_stack = [];
882
883 optimizations.filter(function(i, optim) {
884 var optimization_id = optim.id.replace('optimization_checkbox_', '');
885 var destructive_action_popup = $('#tmpl-wpo-' + optimization_id);
886 return 0 < destructive_action_popup.length;
887 }).each(function(i, maybe_confirm) {
888 var optimization_id = maybe_confirm.id.replace('optimization_checkbox_', '');
889 if (should_user_confirm_action(optimization_id)) {
890 confirmations_stack.push(optimization_id);
891 }
892 });
893
894 user_confirm_destructive_actions_grouped(confirmations_stack, callback);
895 }
896
897 /**
898 * Show confirmation popups for user to accept, in sequence. When done, trigger callback
899 */
900 function user_confirm_destructive_actions_grouped(confirmations_stack, callback) {
901 if (0 < confirmations_stack.length) {
902 var warning_messages = [];
903 confirmations_stack.forEach(function(optimization_id) {
904 var str = $($('#tmpl-wpo-' + optimization_id).html()).children('p').html();
905 warning_messages.push(str);
906 });
907
908 wp_optimize.modal.open(
909 Object.assign(get_destructive_actions_confirm_popup('grouped-warnings'), {
910 cancel: function() {
911 // Nothing will be done
912 },
913 confirm: function() {
914 this.close();
915 callback();
916 },
917 content: function() {
918 return tmpl_wpo_grouped_warnings_tpl.replace('[[warning_messages]]', "<ul><li>" + warning_messages.join("</li><li>") + "</li></ul>");
919 }
920 }
921 ));
922 } else {
923 // No confirmations needed
924 callback();
925 }
926 }
927
928 /**
929 * Pad a string to the left
930 *
931 * @param {string} string The string we want to pad
932 * @param {string} pad Padding character
933 * @param {int} length Padding length
934 * @returns string
935 */
936 function str_pad_left(string, pad, length) {
937 return (new Array(length + 1).join(pad) + string).slice(-length);
938 }
939
940 /**
941 * Shared state for the "load database tables in batches" feature
942 *
943 * @var {object}
944 */
945 var wpoDBTableInfo = {
946 progressText: [],
947 startTime: null,
948 updateTimeout: null,
949 inProgress: false
950 };
951
952 /**
953 * Call AJAX command to load table statuses in batches
954 *
955 * @param {int} offset Query offset
956 * @param {bool} start_clean True when this is the first time the function is called
957 * @param {function} callback Self referenced callback, recursively calls itself until the work is done
958 * @returns void
959 */
960 function load_tables_in_batches(offset, start_clean, callback) {
961 var e = $("#wpo-load-tables-in-batches-progress");
962 var limit = parseInt(wpoptimize.high_table_count_threshold);
963 var start = offset + 1;
964 var end = offset + limit;
965
966 var progress_text = wpoptimize.loading_tables_in_batches.replace('%1$s', start).replace('%2$s', end);
967
968 if (start_clean || (-1 == wpoDBTableInfo.progressText.indexOf(progress_text))) {
969 wpoDBTableInfo.progressText.push(progress_text);
970 e.append($("<div>" + progress_text + "...</div>"));
971 }
972
973 if (5 < e.children().length) {
974 e.children()[0].remove();
975 }
976
977 var spinner = '<img class="wpo-v-middle" height=16 src="'+wpoptimize.spinner_src+'">';
978 var time_left_container = $('#wpo-load-tables-eta');
979 if (true == start_clean) {
980 time_left_container.html(spinner);
981 }
982
983 send_command('load_tables_in_batches', {offset: offset}, function(result) {
984 var now = new Date();
985
986 var time_left = 1 <= result.done ? parseInt(((now - wpoDBTableInfo.startTime) / 1000) / result.done * (result.total - result.done)) : 600;
987 var minutesNum = Math.floor(time_left / 60);
988 var minutes = str_pad_left(minutesNum, '0', 2);
989 var seconds = str_pad_left(time_left - minutesNum * 60, '0', 2);
990
991 time_left_container.html(wpoptimize.time_left.replace('%s', '<span id="wpo-load-tables-time-left" rel="' + time_left + '">' + minutes + ':' + seconds + '</span>') + ' ' + spinner);
992
993 if (null != wpoDBTableInfo.updateTimeout) {
994 clearTimeout(wpoDBTableInfo.updateTimeout);
995 }
996
997 if (true == result.continue) {
998 wpoDBTableInfo.updateTimeout = setTimeout(load_tables_update_time_left, 1000);
999
1000 callback(result.done, false, callback);
1001 } else {
1002 e.html(wpoptimize.done_reloading + '...');
1003 time_left_container.html('');
1004 clearTimeout(wpoDBTableInfo.updateTimeout);
1005 location.reload();
1006 }
1007 }).fail(function() {
1008 if (null != wpoDBTableInfo.updateTimeout) {
1009 clearTimeout(wpoDBTableInfo.updateTimeout);
1010 }
1011 time_left_container.html('');
1012 e.append($("<div>" + wpoptimize.something_wrong_try_again + "</div>"));
1013
1014 wpoDBTableInfo.inProgress = false;
1015 $('#wpo-load-tables-in-batches-button').prop('disabled', false);
1016 });
1017 }
1018
1019 /**
1020 * While AJAX operation runs in background, update time left every second in front-end
1021 *
1022 * @returns void
1023 */
1024 function load_tables_update_time_left() {
1025 var time_left_container = $('#wpo-load-tables-time-left');
1026 var current_time_left = Math.max(0, parseInt(time_left_container.attr('rel')) - 1);
1027
1028 var minutesNum = Math.floor(current_time_left / 60);
1029 var minutes = str_pad_left(minutesNum, '0', 2);
1030 var seconds = str_pad_left(current_time_left - minutesNum * 60, '0', 2);
1031
1032 time_left_container.html(minutes + ':' + seconds);
1033 time_left_container.attr('rel', current_time_left);
1034
1035 wpoDBTableInfo.updateTimeout = setTimeout(load_tables_update_time_left, 1000);
1036 }
1037
1038 /**
1039 * Check if we need to show the table load popup and show it
1040 * Skips auto-opening while the onboarding wizard is active.
1041 *
1042 * @param {string} active_tab Only show popup when active_tab='optimize'
1043 * @returns void
1044 */
1045 function maybe_show_too_many_tables_popup(active_tab) {
1046
1047 var $modal = $('#wpo-too-many-tables-popup');
1048
1049 function openTooManyTablesModal(autoShown) {
1050 // Move the modal to <body> so it isn't hidden by a display:none tab wrapper.
1051 if (!$modal.parent().is('body')) {
1052 $('body').append($modal);
1053 }
1054 $modal.show();
1055 $('body').addClass('wpo-modal-is-opened');
1056 var $closeBtn = $modal.find('.wpo-too-many-tables-close');
1057 var $bg = $modal.find('.wpo-modal--bg');
1058 $closeBtn.off('click.wpoModal');
1059 $bg.off('click.wpoModal');
1060 if (autoShown) {
1061 $closeBtn.on('click.wpoModal', function() { location.href = 'plugins.php'; });
1062 } else {
1063 $closeBtn.add($bg).on('click.wpoModal', function() {
1064 $modal.hide();
1065 $('body').removeClass('wpo-modal-is-opened');
1066 });
1067 }
1068 }
1069
1070 if ('optimize' === active_tab && 'undefined' !== typeof wpo_too_many_tables && true === wpo_too_many_tables && 'undefined' !== typeof wpo_onboarding_active && true !== wpo_onboarding_active) {
1071 $(document).ready(function() { openTooManyTablesModal(true); });
1072 }
1073
1074 $('#wpo-load-tables-in-batches').off('click.wpoLoadTablesModal').on('click.wpoLoadTablesModal', function() {
1075 openTooManyTablesModal(false);
1076 });
1077
1078 $('#wpo-load-tables-in-batches-button').off('click.wpoLoadTablesInBatches').on('click.wpoLoadTablesInBatches', function() {
1079 if (wpoDBTableInfo.inProgress) return;
1080
1081 wpoDBTableInfo.inProgress = true;
1082 $(this).prop('disabled', true);
1083 wpoDBTableInfo.startTime = new Date();
1084
1085 load_tables_in_batches(wpo_table_scan_offset, true, function() {
1086 load_tables_in_batches.apply({}, arguments);
1087 });
1088 });
1089 }
1090
1091 /**
1092 * Sent command to run selected optimizations and auto backup if selected
1093 *
1094 * @return void
1095 */
1096 function run_optimizations() {
1097 var auto_backup = false;
1098
1099 if ($('#enable-auto-backup').is(":checked")) {
1100 auto_backup = true;
1101 }
1102
1103 // Save the click option.
1104 save_auto_backup_options();
1105
1106 // Only run the backup if tick box is checked.
1107 if (auto_backup == true) {
1108 take_a_backup_with_updraftplus(run_optimization);
1109 } else {
1110 // Run optimizations.
1111 run_optimization();
1112 }
1113 }
1114
1115 /**
1116 * Take a backup with UpdraftPlus if possible.
1117 *
1118 * @param {Function} callback
1119 * @param {String} file_entities
1120 *
1121 * @return void
1122 */
1123 function take_a_backup_with_updraftplus(callback, file_entities) {
1124 // Set default for file_entities to empty string
1125 if ('undefined' == typeof file_entities) file_entities = '';
1126 var exclude_files = file_entities ? 0 : 1;
1127
1128 if (typeof updraft_backupnow_inpage_go === 'function') {
1129 updraft_backupnow_inpage_go(function () {
1130 // Close the backup dialogue.
1131 $('#updraft-backupnow-inpage-modal').dialog('close');
1132
1133 if (callback) callback();
1134
1135 }, file_entities, 'autobackup', 0, exclude_files, 0, wpoptimize.automatic_backup_before_optimizations);
1136 } else {
1137 if (callback) callback();
1138 }
1139 }
1140
1141 /**
1142 * Save all auto backup options.
1143 *
1144 * @return void
1145 */
1146 function save_auto_backup_options() {
1147 var options = gather_settings('object');
1148 options['auto_backup'] = $('#enable-auto-backup').is(":checked");
1149
1150 send_command('save_auto_backup_option', options);
1151 }
1152
1153 // Show/hide sites list for multi-site settings.
1154 var wpo_settings_sites_list = $('#wpo_settings_sites_list'),
1155 wpo_settings_sites_list_ul = wpo_settings_sites_list.find('ul').first(),
1156 wpo_settings_sites_list_items = $('input[type="checkbox"]', wpo_settings_sites_list_ul),
1157 wpo_settings_all_sites_checkbox = wpo_settings_sites_list.find('#wpo_all_sites'),
1158 wpo_sitelist_show_moreoptions_link = $('#wpo_sitelist_show_moreoptions'),
1159 wpo_sitelist_moreoptions_div = $('#wpo_sitelist_moreoptions'),
1160
1161 wpo_settings_sites_list_cron = $('#wpo_settings_sites_list_cron'),
1162 wpo_settings_sites_list_cron_ul = wpo_settings_sites_list_cron.find('ul').first(),
1163 wpo_settings_sites_list_cron_items = $('input[type="checkbox"]', wpo_settings_sites_list_cron_ul),
1164 wpo_settings_all_sites_cron_checkbox = wpo_settings_sites_list_cron.find('#wpo_all_sites_cron'),
1165 wpo_sitelist_show_moreoptions_cron_link = $('#wpo_sitelist_show_moreoptions_cron'),
1166 wpo_sitelist_moreoptions_cron_div = $('#wpo_sitelist_moreoptions_cron');
1167
1168 // sites list for manual run.
1169 define_moreoptions_settings(
1170 wpo_sitelist_show_moreoptions_link,
1171 wpo_sitelist_moreoptions_div,
1172 wpo_settings_all_sites_checkbox,
1173 wpo_settings_sites_list_items
1174 );
1175
1176 var debounceTimer;
1177
1178 $([wpo_settings_all_sites_checkbox, wpo_settings_sites_list_items]).each(function() {
1179 $(this).on('change', function() {
1180 clearTimeout(debounceTimer);
1181 debounceTimer = setTimeout(function() {
1182 update_optimizations_info();
1183 }, 1000);
1184 });
1185 });
1186
1187 // sites list for cron run.
1188 define_moreoptions_settings(
1189 wpo_sitelist_show_moreoptions_cron_link,
1190 wpo_sitelist_moreoptions_cron_div,
1191 wpo_settings_all_sites_cron_checkbox,
1192 wpo_settings_sites_list_cron_items
1193 );
1194
1195 /**
1196 * Attach event handlers for more options list showed by clicking on show_moreoptions_link.
1197 *
1198 * @param show_moreoptions_link
1199 * @param more_options_div
1200 * @param all_items_checkbox
1201 * @param items_list
1202 *
1203 * @return boolean
1204 */
1205 function define_moreoptions_settings(show_moreoptions_link, more_options_div, all_items_checkbox, items_list) {
1206 // toggle show options on click.
1207 show_moreoptions_link.on('click', function () {
1208 if (!more_options_div.hasClass('wpo_always_visible')) more_options_div.toggleClass('wpo_hidden');
1209 return false;
1210 });
1211
1212 // if "all items" checked/unchecked then check/uncheck items in the list.
1213 define_select_all_checkbox(all_items_checkbox, items_list);
1214 }
1215
1216 /**
1217 * Defines "select all" check box, where all_items_checkbox is a select all check box jQuery object
1218 * and items_list is a list of checkboxes assigned with all_items_checkbox.
1219 *
1220 * @param {Object} all_items_checkbox
1221 * @param {Object} items_list
1222 *
1223 * @return void
1224 */
1225 function define_select_all_checkbox(all_items_checkbox, items_list) {
1226 // if "all items" checked/unchecked then check/uncheck items in the list.
1227 all_items_checkbox.on('change', function () {
1228 if (all_items_checkbox.is(':checked')) {
1229 items_list.prop('checked', true);
1230 } else {
1231 items_list.prop('checked', false);
1232 }
1233
1234 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
1235 });
1236
1237 items_list.on('change', function () {
1238 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
1239 });
1240
1241 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
1242
1243 }
1244
1245 /**
1246 * Update state of "all items" checkbox depends on state all items in the list.
1247 *
1248 * @param all_items_checkbox
1249 * @param all_items
1250 *
1251 * @return void
1252 */
1253 function update_wpo_all_items_checkbox_state(all_items_checkbox, all_items) {
1254 var all_items_count = 0, checked_items_count = 0;
1255
1256 all_items.each(function () {
1257 if ($(this).is(':checked')) {
1258 checked_items_count++;
1259 }
1260 all_items_count++;
1261 });
1262
1263 // update label text if need.
1264 if (all_items_checkbox.next().is('label') && all_items_checkbox.next().data('label')) {
1265 var label = all_items_checkbox.next(),
1266 label_mask = label.data('label');
1267
1268 if (all_items_count == checked_items_count) {
1269 label.text(label_mask);
1270 } else {
1271 label.text(label_mask.replace('all', [checked_items_count, ' of ', all_items_count].join('')));
1272 }
1273 }
1274
1275 if (all_items_count == checked_items_count) {
1276 all_items_checkbox.prop('checked', true);
1277 } else {
1278 all_items_checkbox.prop('checked', false);
1279 }
1280 }
1281
1282 /**
1283 * Running the optimizations for the selected options
1284 *
1285 * @return {[type]} optimizations
1286 */
1287 function run_optimization() {
1288 var optimizations = $('#optimizations_list .optimization_checkbox:checked').toArray();
1289
1290 var sorted_optimizations = optimizations.sort(function (a, b) {
1291 var aOrder = $(a).closest('.wp-optimize-settings').data('optimization_run_sort_order');
1292 var bOrder = $(b).closest('.wp-optimize-settings').data('optimization_run_sort_order');
1293 return aOrder - bOrder; // Ascending order - so all other optimizations will run before optimizetables
1294 });
1295
1296 var optimization_options = {};
1297
1298 sorted_optimizations.forEach(function (element) {
1299 var optimization_id = $(element).closest('.wp-optimize-settings').data('optimization_id');
1300 if (!optimization_id) {
1301 console.log("Optimization ID corresponding to pressed button not found");
1302 return;
1303 }
1304 // An empty object - in future, options may be implemented.
1305 optimization_options[optimization_id] = { active: 1 };
1306 do_optimization(optimization_id);
1307 });
1308
1309 send_command('save_manual_run_optimization_options', optimization_options);
1310 }
1311
1312 /**
1313 * Uptate the tables list
1314 *
1315 * @param {object} response
1316 */
1317 function update_tables_list(response) {
1318 if (response.hasOwnProperty('table_list')) {
1319 var resort = true,
1320 // add a callback, as desired
1321 callback = function(table) {
1322 $('#wpoptimize_table_list tbody').css('opacity', '1');
1323 };
1324
1325 // update body with new content.
1326 $("#wpoptimize_table_list tbody").remove();
1327 $("#wpoptimize_table_list tfoot").remove();
1328 $("#wpoptimize_table_list thead").after(response.table_list);
1329
1330 $("#wpoptimize_table_list").trigger("updateAll", [resort, callback]);
1331 }
1332
1333 if (response.hasOwnProperty('total_size')) {
1334 $('#optimize_current_db_size').html(response.total_size);
1335 }
1336
1337 if (response.hasOwnProperty('show_innodb_force_optimize')) {
1338 $('.innodb_force_optimize--container').toggleClass('hidden', !response.show_innodb_force_optimize);
1339 }
1340
1341 change_actions_column_visibility();
1342 update_single_table_optimization_buttons(force_single_table_optimization);
1343 }
1344
1345 $('#wp_optimize_table_list_refresh').on('click', function (e) {
1346 e.preventDefault();
1347 // Tables are not available until the batch scan completes — open the scan popup instead.
1348 if (true === wpo_too_many_tables) {
1349 var scanBtn = document.getElementById('wpo-load-tables-in-batches');
1350 if (scanBtn) scanBtn.click();
1351 return;
1352 }
1353 var shade = $(this).closest('.wpo-tab-postbox').find('.wpo_shade');
1354 shade.removeClass('hidden');
1355 $('#wpoptimize_table_list tbody').css('opacity', '0.5');
1356 send_command('get_table_list', {refresh_plugin_json: true}, update_tables_list).always(function() {
1357 shade.addClass('hidden');
1358 });
1359 });
1360
1361 $('#wpo-404-detector-form').on('click', '#wpo-404-clear-logs', function (e) {
1362 e.preventDefault();
1363 block_ui(wpoptimize.please_wait);
1364 send_command('truncate_404_logs', {}, function (resp) {
1365 if (resp && resp.hasOwnProperty('success') && resp.success) {
1366 $('#wpo_404_detector_results').html('');
1367 }
1368 if (resp && resp.hasOwnProperty('message') && resp.message) {
1369 block_ui(resp.message, {}, 3000);
1370 }
1371 }).fail(function() {
1372 block_ui(wpoptimize.something_wrong_try_again, {}, 3000);
1373 });
1374 });
1375
1376
1377 $('#database_settings_form, #settings_form, #wpo-404-detector-form').on('click', '.wpo-save-settings', function (e) {
1378 e.preventDefault();
1379 var form = $(this).closest('form');
1380 var spinner = form.find('.wpo-saving-settings');
1381 var form_data = gather_settings();
1382
1383 form.trigger('wpo-saving-form-data');
1384
1385 if (form.form_errors.has_errors()) return;
1386
1387 spinner.show();
1388 block_ui(wpoptimize.saving);
1389
1390 // when optimizations list in the document - send information about selected optimizations.
1391 if ($('#optimizations_list').length) {
1392 $('#optimizations_list .optimization_checkbox:checked').each(function() {
1393 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
1394 if (optimization_id) {
1395 form_data += '&optimization-options['+optimization_id+'][active]=1';
1396 }
1397 });
1398 }
1399
1400 if ($('#purge_cache_permissions').length) {
1401 if (!$('#purge_cache_permissions').val()) {
1402 form_data += '&purge_cache_permissions[]';
1403 }
1404 }
1405
1406 send_command('save_settings', form_data, function (resp) {
1407 spinner.closest('div').find('.save-done').show().delay(5000).fadeOut();
1408
1409 if (resp && resp.hasOwnProperty('save_results') && resp.save_results && resp.save_results.hasOwnProperty('errors')) {
1410 for (var i = 0, len = resp.save_results.errors.length; i < len; i++) {
1411 var new_html = '<div class="error">' + resp.errors[i] + '</div>';
1412 temporarily_display_notice(new_html, '#wp-optimize-settings-save-results');
1413 }
1414 }
1415 if (resp && resp.hasOwnProperty('status_box_contents')) {
1416 $(resp.status_box_contents).each(function(index, el) {
1417 if ($(el).is('#wp_optimize_status_box')) {
1418 $('#wp_optimize_status_box').replaceWith($(el));
1419 }
1420 });
1421 }
1422
1423 if (resp && resp.hasOwnProperty('optimizations_table')) {
1424 $('#optimizations_list').replaceWith(resp.optimizations_table);
1425 }
1426
1427 if (resp && resp.hasOwnProperty('settings_auto_cleanup_contents')) {
1428 $('#wpo_auto_cleanup').replaceWith(resp.settings_auto_cleanup_contents);
1429 WPO_Select2();
1430 }
1431
1432 if (resp && resp.hasOwnProperty('logging_settings_contents')) {
1433 $('#wpo_logging_settings').replaceWith(resp.logging_settings_contents);
1434 }
1435
1436 // switch for visibility (performance tab).
1437 var $wpo_404_detector_btn = $('#wpo_404_detector');
1438 $wpo_404_detector_btn.prop('checked', !$wpo_404_detector_btn.prop('checked'));
1439 var $wpo_404_detector_results = $('#wpo_404_detector_results');
1440 $wpo_404_detector_results.css('display', $wpo_404_detector_btn.prop('checked') ? 'block' : 'none');
1441
1442 // Need to refresh the page if enable-admin-menu tick state has changed.
1443 if (resp.save_results.refresh) {
1444 location.reload();
1445 }
1446 }).always(function() {
1447 spinner.hide();
1448 $.unblockUI();
1449 });
1450 });
1451
1452 $('#database_settings_form').on('click', '.wpo_save_event', function() {
1453 setTimeout(function(){
1454 $('#wp-optimize-save-database-settings').trigger('click');
1455 }, 500);
1456 });
1457
1458 $('#settings_form').on('click', '.wpo_save_logging', function() {
1459 setTimeout(function(){
1460 $('#wp-optimize-save-main-settings').trigger('click');
1461 }, 500);
1462 });
1463
1464 /*
1465 * Handle Wipe Settings click.
1466 */
1467 $('#settings_form').on('click', '.wpo-wipe-settings', function() {
1468 var spinner = $(this).parent().find('.wpo_spinner');
1469
1470 spinner.show();
1471
1472 send_command('wipe_settings', {}, function() {
1473 spinner.next().removeClass('display-none').delay(5000).fadeOut();
1474 alert(wpoptimize.settings_have_been_deleted_successfully);
1475 location.replace(wpoptimize.settings_page_url);
1476 }).always(function() {
1477 spinner.hide();
1478 });
1479
1480 });
1481
1482 $('#wp-optimize-wrap').on('click', '#wp_optimize_status_box_refresh', function (e) {
1483 e.preventDefault();
1484 $('#wp_optimize_status_box').css('opacity', '0.5');
1485 send_command('get_status_box_contents', null, function (resp) {
1486 $('#wp_optimize_status_box').css('opacity', '1');
1487 $(resp).each(function(index, el) {
1488 if ($(el).is('#wp_optimize_status_box')) {
1489 $('#wp_optimize_status_box').replaceWith($(el));
1490 }
1491 });
1492
1493 });
1494 });
1495
1496 /**
1497 * Run single table optimization. Handle click on Optimize button.
1498 *
1499 * @param {Object} btn jQuery object clicked Optimize button
1500 *
1501 * @return {void}
1502 */
1503 function run_single_table_optimization(btn) {
1504 var spinner = btn.next(),
1505 action_done_icon = spinner.next(),
1506 table_name = btn.data('table'),
1507 table_type = btn.data('type'),
1508 data = {
1509 optimization_id: 'optimizetables',
1510 optimization_table: table_name,
1511 optimization_table_type: table_type
1512 };
1513 btn.hide();
1514 // if checked force button then send force value.
1515 if (force_single_table_optimization) {
1516 data['optimization_force'] = true;
1517 }
1518
1519 spinner.removeClass('visibility-hidden');
1520
1521 send_command('do_optimization', { optimization_id: 'optimizetables', data: data }, function (response) {
1522 if (response.result.meta.error) {
1523 btn.closest('tr').html('<td colspan="8" class="no-table"><p>' + response.result.meta.message + '</p></td>');
1524 setTimeout(function() {
1525 $('#wp_optimize_table_list_refresh').trigger('click');
1526 }, 2000);
1527 } else {
1528 if (response.result.meta.tableinfo) {
1529 var row = btn.closest('tr'),
1530 meta = response.result.meta,
1531 tableinfo = meta.tableinfo;
1532
1533 update_single_table_information(row, tableinfo);
1534
1535 // update total overhead.
1536 $('#wpoptimize_table_list > tbody:last th:eq(6)').html(['<span style="color:', meta.overhead > 0 ? '#0000FF' : '#004600', '">', meta.overhead_formatted,'</span>'].join(''));
1537 }
1538 }
1539
1540 btn.prop('disabled', false);
1541 spinner.addClass('visibility-hidden');
1542 action_done_icon.show().removeClass('visibility-hidden').delay(2500).fadeOut('fast', function() {
1543 btn.show();
1544 action_done_icon.show().addClass('visibility-hidden');
1545 });
1546 });
1547 }
1548
1549 /**
1550 * Update information about single table in the database tables list.
1551 *
1552 * @param {Object} row jQuery object for TR html tag.
1553 * @param {Object} tableinfo
1554 *
1555 * @return {void}
1556 */
1557 function update_single_table_information(row, tableinfo) {
1558 // update table information in row.
1559 $('td:eq(2)', row).text(tableinfo.rows);
1560 $('td:eq(3)', row).text(tableinfo.data_size);
1561 $('td:eq(4)', row).text(tableinfo.index_size);
1562 $('td:eq(5)', row).text(tableinfo.type);
1563
1564 if (tableinfo.is_optimizable) {
1565 $('td:eq(6)', row).html(['<span style="color:', tableinfo.overhead > 0 ? '#0000FF' : '#004600', '">', tableinfo.overhead,'</span>'].join(''));
1566 } else {
1567 $('td:eq(6)', row).html('<span color="#0000FF">-</span>');
1568 }
1569
1570 }
1571
1572 /**
1573 * Update single table optimization buttons state depends on force_optimization value.
1574 *
1575 * @param {boolean} force_optimization See if we need to force optimization
1576 *
1577 * @return {void}
1578 */
1579 function update_single_table_optimization_buttons(force_optimization) {
1580 $('.run-single-table-optimization').each(function() {
1581 var btn = $(this);
1582
1583 if (btn.data('disabled')) {
1584 if (force_optimization) {
1585 btn.prop('disabled', false);
1586 } else {
1587 btn.prop('disabled', true);
1588 }
1589 }
1590 });
1591 }
1592
1593 /**
1594 * Returns true if single site mode or multisite and at least one site selected;
1595 *
1596 * @return {boolean}
1597 */
1598 function is_sites_selected() {
1599 return (0 == wpo_settings_sites_list.length || 0 != $('input[type="checkbox"]:checked', wpo_settings_sites_list).length);
1600 }
1601
1602 /**
1603 * Update optimizations info texts.
1604 *
1605 * @param {Object} response object returned by command get_optimizations_info.
1606 *
1607 * @return {void}
1608 */
1609 function update_optimizations_info_view(response) {
1610 var i, dom_id, info;
1611
1612 // @codingStandardsIgnoreLine
1613 if (!response) return;
1614
1615 for (i in response) {
1616 if (!response.hasOwnProperty(i)) continue;
1617
1618 dom_id = ['#wp-optimize-settings-', response[i].dom_id].join('');
1619 info = response[i].info ? response[i].info : '';
1620
1621 $(dom_id + ' .wp-optimize-settings-optimization-info').html(info);
1622 }
1623 }
1624
1625 var get_optimizations_info_cache = {};
1626
1627 /**
1628 * Send command for get optimizations info and update view.
1629 *
1630 * @return {void}
1631 */
1632 function update_optimizations_info() {
1633 var cache_key = ['', get_selected_sites_list().join('_')].join('');
1634
1635 // if information saved in cache show it.
1636 if (get_optimizations_info_cache.hasOwnProperty(cache_key)) {
1637 update_optimizations_info_view(get_optimizations_info_cache[cache_key]);
1638 } else {
1639 // else send command update cache and update view.
1640 send_command('get_optimizations_info', {'wpo-sites':get_selected_sites_list()}, function(response) {
1641 // @codingStandardsIgnoreLine
1642 if (!response) return;
1643 get_optimizations_info_cache[cache_key] = response;
1644 update_optimizations_info_view(response);
1645 });
1646 }
1647 }
1648
1649 /*
1650 * Check if settings file selected for import.
1651 */
1652 $('#wpo_import_settings_btn').on('click', function(e) {
1653 var file_input = $('#wpo_import_settings_file'),
1654 filename = file_input.val(),
1655 wpo_import_file_file = file_input[0].files[0],
1656 wpo_import_file_reader = new FileReader();
1657
1658 $('#wpo_import_settings_btn').prop('disabled', true);
1659
1660 if (!/\.json$/.test(filename)) {
1661 e.preventDefault();
1662 $('#wpo_import_settings_btn').prop('disabled', false);
1663 $('#wpo_import_error_message').text(wpoptimize.please_select_settings_file).slideDown();
1664 return false;
1665 }
1666
1667 wpo_import_file_reader.onload = function() {
1668 import_settings(this.result);
1669 };
1670
1671 wpo_import_file_reader.readAsText(wpo_import_file_file);
1672
1673 return false;
1674 });
1675
1676 /**
1677 * Send import settings command.
1678 *
1679 * @param {string} settings encoded settings in json string.
1680 *
1681 * @return {void}
1682 */
1683 function import_settings(settings) {
1684 var loader = $('#wpo_import_spinner'),
1685 success_message = $('#wpo_import_success_message'),
1686 error_message = $('#wpo_import_error_message');
1687
1688 loader.show();
1689 send_command('import_settings', {'settings': settings}, function(response) {
1690 loader.hide();
1691 if (response && response.errors && response.errors.length) {
1692 error_message.text(response.errors.join('<br>'));
1693 error_message.slideDown();
1694 } else if (response && response.messages && response.messages.length) {
1695 success_message.text(response.messages.join('<br>'));
1696 success_message.slideDown();
1697 setTimeout(function() {
1698 window.location.reload();
1699 }, 500);
1700 }
1701
1702 $('#wpo_import_settings_btn').prop('disabled', false);
1703 });
1704 }
1705
1706 /*
1707 * Hide file validation message on change file field value.
1708 */
1709 $('#wpo_import_settings_file').on('change', function() {
1710 $('#wpo_import_error_message').slideUp();
1711 });
1712
1713 /*
1714 * Save settings to hidden form field, used for export.
1715 */
1716 $('#wpo_export_settings_btn').on('click', function(e) {
1717 wpo_download_json_file(gather_settings('object'));
1718 return false;
1719 });
1720
1721 /**
1722 * Force download json file with posted data.
1723 *
1724 * @param {Object} data data to put in a file.
1725 * @param {string} filename
1726 *
1727 * @return {void}
1728 */
1729 function wpo_download_json_file(data ,filename) {
1730 // Attach this data to an anchor on page
1731 var link = document.body.appendChild(document.createElement('a')),
1732 date = new Date(),
1733 year = date.getFullYear(),
1734 month = date.getMonth() < 10 ? ['0', date.getMonth()].join('') : date.getMonth(),
1735 day = date.getDay() < 10 ? ['0', date.getDay()].join('') : date.getDay();
1736
1737 filename = filename ? filename : ['wpo-settings-',year,'-',month,'-',day,'.json'].join('');
1738
1739 link.setAttribute('download', filename);
1740 link.setAttribute('style', "display:none;");
1741 link.setAttribute('href', 'data:text/json' + ';charset=UTF-8,' + encodeURIComponent(JSON.stringify(data)));
1742 link.click();
1743 }
1744
1745 /**
1746 * Make ajax request to get optimization info.
1747 *
1748 * @param {Object} optimization_info_container - jquery object obtimization info container.
1749 * @param {string} optimization_id - optimization id.
1750 * @param {Object} params - custom params posted to optimization get info.
1751 *
1752 * @return void
1753 */
1754 var optimization_get_info = function(optimization_info_container, optimization_id, params) {
1755 return send_command('get_optimization_info', {optimization_id: optimization_id, data: params}, function(resp) {
1756 var meta = (resp && resp.result && resp.result.meta) ? resp.result.meta : {},
1757 message = (resp && resp.result && resp.result.output) ? resp.result.output.join('<br>') : '...';
1758
1759 // trigger event about optimization get info in process.
1760 $(document).trigger(['optimization_get_info_', optimization_id].join(''), [message, meta]);
1761 // update status message in optimizations list.
1762 optimization_info_container.html(message);
1763
1764 if (!meta.finished) {
1765 setTimeout(function() {
1766 var xhr = optimization_get_info(optimization_info_container, optimization_id, meta);
1767 $(document).trigger(['optimization_get_info_xhr_', optimization_id].join(''), [xhr, meta]);
1768 }, 1);
1769 } else {
1770 // trigger event about optimization get info action done.
1771 $(document).trigger(['optimization_get_info_', optimization_id, '_done'].join(''), resp);
1772 }
1773 });
1774 };
1775
1776 // attach event handlers after database tables template loaded.
1777 // Handle single optimization click.
1778 $('#wpoptimize_table_list').on('click', '.run-single-table-optimization', function () {
1779 var take_backup_checkbox = $('#enable-auto-backup-1'),
1780 button = $(this);
1781
1782 // check if backup checkbox is checked for db tables
1783 if (take_backup_checkbox.is(':checked')) {
1784 take_a_backup_with_updraftplus(
1785 function () {
1786 run_single_table_optimization(button);
1787 }
1788 );
1789 } else {
1790 run_single_table_optimization(button);
1791 }
1792 });
1793
1794 // Handle repair table click
1795 $('#wpoptimize_table_list').on('click', '.run-single-table-repair', function () {
1796 var btn = $(this),
1797 spinner = btn.next(),
1798 action_done_icon = spinner.next(),
1799 table_name = btn.data('table'),
1800 data = {
1801 optimization_id: 'repairtables',
1802 optimization_table: table_name
1803 };
1804
1805 spinner.removeClass('visibility-hidden');
1806
1807 send_command('do_optimization', {optimization_id: 'repairtables', data: data}, function (response) {
1808 if (response.result.meta.success) {
1809 var row = btn.closest('tr'),
1810 tableinfo = response.result.meta.tableinfo;
1811
1812 btn.prop('disabled', false);
1813 spinner.addClass('visibility-hidden');
1814 action_done_icon.show().removeClass('visibility-hidden');
1815
1816 update_single_table_information(row, tableinfo);
1817
1818 // keep visible results from previous operation for one second and show optimize button if possible.
1819 setTimeout(function () {
1820 var parent_td = btn.closest('td'),
1821 btn_wrap = btn.closest('.wpo_button_wrap');
1822
1823 // remove Repair button and show Optimize button.
1824 btn_wrap.fadeOut('fast', function () {
1825 btn_wrap.closest('.wpo_button_wrap').remove();
1826
1827 // if table type is supported for optimization then show OPTIMIZE button.
1828 if (tableinfo.is_type_supported) {
1829 $('.wpo_button_wrap', parent_td).removeClass('wpo_hidden');
1830 }
1831 });
1832
1833 change_actions_column_visibility();
1834 }, 1000);
1835 } else {
1836 btn.prop('disabled', false);
1837 spinner.addClass('visibility-hidden');
1838 alert(wpoptimize.table_was_not_repaired.replace('%s', table_name));
1839 }
1840 });
1841 });
1842
1843 // Handle convert table click
1844 $('#wpoptimize_table_list').on('click', '.toinnodb', function () {
1845 convert_single_db_table($(this));
1846 });
1847
1848 var table_to_remove_btn;
1849
1850 // Handle delete table click
1851 $('#wpoptimize_table_list').on('click', '.run-single-table-delete', function () {
1852 table_to_remove_btn = $(this);
1853 var take_backup_checkbox = $('#enable-auto-backup-1');
1854 if ('' == wpoptimize.user_always_ignores_table_deletion_warning || '1' !== wpoptimize.user_always_ignores_table_deletion_warning) {
1855 wp_optimize.modal.open({
1856 className: 'wpo-confirm',
1857 events: {
1858 'click .wpo-modal--bg': 'close',
1859 'click .delete-table': 'deleteTable',
1860 'change #confirm_deletion_without_backup': 'changeConfirm',
1861 'change #confirm_table_deletion': 'changeConfirm'
1862 },
1863 content: function() {
1864 var content_template = wp.template('wpo-table-delete');
1865 // Get the plugins list
1866 var plugins_list = table_to_remove_btn.closest('tr').find('.table-plugins').html();
1867 return content_template({
1868 no_backup: !take_backup_checkbox.is(':checked'),
1869 plugins_list: plugins_list,
1870 table_name: table_to_remove_btn.data('table')
1871 });
1872 },
1873 changeConfirm: function() {
1874 var enable_button = true;
1875 var backup_input = this.$('#confirm_deletion_without_backup');
1876 var confirm_input = this.$('#confirm_table_deletion');
1877 if (backup_input.length && !backup_input.is(':checked')) {
1878 enable_button = false;
1879 }
1880 if (!confirm_input.is(':checked')) {
1881 enable_button = false;
1882 }
1883 this.$('.delete-table').prop('disabled', !enable_button);
1884 },
1885 deleteTable: function() {
1886 // check if user ignore table warning
1887 var ignores_table_deletion_warning_checkbox = this.$('#ignores_table_deletion_warning');
1888 if (ignores_table_deletion_warning_checkbox.is(':checked')) {
1889 send_command('user_ignores_table_deletion_warning', {}, function(response) {
1890 if (response.success) {
1891 wpoptimize.user_always_ignores_table_deletion_warning = '1';
1892 }
1893 });
1894 }
1895 // check if backup checkbox is checked for db tables
1896 if (take_backup_checkbox.is(':checked')) {
1897 take_a_backup_with_updraftplus(remove_single_db_table);
1898 } else {
1899 remove_single_db_table();
1900 }
1901 this.close();
1902
1903 }
1904 });
1905 } else {
1906 // check if backup checkbox is checked for db tables
1907 if (take_backup_checkbox.is(':checked')) {
1908 take_a_backup_with_updraftplus(remove_single_db_table);
1909 } else {
1910 remove_single_db_table();
1911 }
1912 }
1913 });
1914
1915 /**
1916 * Send ajax command to convert single table to InnoDB.
1917 *
1918 * @param {Object} btn jQuery object of clicked "Convert to InnoDB" button.
1919 *
1920 * @return void
1921 */
1922 function convert_single_db_table(table_to_convert_btn) {
1923 var spinner = table_to_convert_btn.next(),
1924 action_done_icon = spinner.next(),
1925 table_name = table_to_convert_btn.data('table'),
1926 data = {
1927 optimization_id: 'orphanedtables',
1928 optimization_table: table_name,
1929 optimization_action: 'toinnodb'
1930 };
1931
1932 spinner.removeClass('visibility-hidden');
1933
1934 send_command('do_optimization', { optimization_id: 'orphanedtables', data: data }, function (response) {
1935 if (response.result.meta.error) {
1936 table_to_convert_btn.closest('tr').html('<td colspan="8" class="no-table"><p>' + response.result.meta.message + '</p></td>');
1937 setTimeout(function() {
1938 $('#wp_optimize_table_list_refresh').trigger('click');
1939 }, 2000);
1940 return;
1941 }
1942 if (response.result.meta.success) {
1943 var row = table_to_convert_btn.closest('tr');
1944
1945 action_done_icon.show().removeClass('visibility-hidden');
1946
1947 // remove convert to Innodb button.
1948 row.find(".toinnodb").remove();
1949
1950
1951 setTimeout(function() {
1952 action_done_icon.fadeOut('slow', function() {
1953 row.find("[data-colname='Type']").text("InnoDB");
1954 });
1955 }, 500);
1956 } else {
1957 var message = wpoptimize.table_was_not_converted.replace('%s', table_name);
1958
1959 if (response.result.meta.message) {
1960 message += '(' + response.result.meta.message + ')';
1961 }
1962
1963 alert(message);
1964 }
1965 }).always(function() {
1966 table_to_convert_btn.prop('disabled', false);
1967 spinner.addClass('visibility-hidden');
1968 });
1969 }
1970
1971
1972
1973 /**
1974 * Send ajax command to remove single database table.
1975 *
1976 * @param {Object} btn jQuery object of clicked "Remove" button.
1977 *
1978 * @return void
1979 */
1980 function remove_single_db_table() {
1981 var spinner = table_to_remove_btn.next(),
1982 action_done_icon = spinner.next(),
1983 table_name = table_to_remove_btn.data('table'),
1984 data = {
1985 optimization_id: 'orphanedtables',
1986 optimization_table: table_name
1987 };
1988
1989 spinner.removeClass('visibility-hidden');
1990
1991 send_command('do_optimization', { optimization_id: 'orphanedtables', data: data }, function (response) {
1992 if (response.result.meta.success) {
1993 var row = table_to_remove_btn.closest('tr');
1994
1995 action_done_icon.show().removeClass('visibility-hidden');
1996
1997 // remove row for deleted table.
1998 setTimeout(function() {
1999 row.fadeOut('slow', function() {
2000 row.remove();
2001
2002 change_actions_column_visibility();
2003 });
2004 }, 500);
2005 } else {
2006 var message = wpoptimize.table_was_not_deleted.replace('%s', table_name);
2007
2008 if (response.result.meta.message) {
2009 message += '(' + response.result.meta.message + ')';
2010 }
2011
2012 alert(message);
2013 }
2014 }).always(function() {
2015 table_to_remove_btn.prop('disabled', false);
2016 spinner.addClass('visibility-hidden');
2017 });
2018 }
2019
2020 change_actions_column_visibility();
2021
2022 /**
2023 * Show or hide actions column if need.
2024 *
2025 * @return void
2026 */
2027 function change_actions_column_visibility() {
2028 var table = $('#wpoptimize_table_list'),
2029 hideLastColumn = true;
2030
2031 // check if any button exists in the actions column.
2032 $('tr', table).each(function() {
2033 var row = $(this);
2034
2035 if ($('button', row).length > 0) {
2036 hideLastColumn = false;
2037 return false;
2038 }
2039 });
2040
2041 // hide or show last column
2042 $('tr', table).each(function() {
2043 var row = $(this);
2044
2045 if (hideLastColumn) {
2046 $('td:last, th:last', row).hide();
2047 } else {
2048 $('td:last, th:last', row).show();
2049 }
2050 });
2051 }
2052
2053 /*
2054 * Validate general settings (loggers).
2055 */
2056 $('#wp-optimize-general-settings').on('wpo-saving-form-data', function() {
2057 var valid = true;
2058 var $form = $(this);
2059
2060 $('.wpo_logger_addition_option, .wpo_logger_type').each(function() {
2061 if (!validate_field($(this), true)) {
2062 valid = false;
2063 $(this).addClass('wpo_error_field');
2064 } else {
2065 $(this).removeClass('wpo_error_field');
2066 }
2067 });
2068
2069 if (!valid) {
2070 $form.form_errors.add('missing-fields', '');
2071 $('#wp-optimize-settings-save-results')
2072 .show()
2073 .addClass('wpo_alert_notice')
2074 .text(wpoptimize.fill_all_settings_fields)
2075 .delay(5000)
2076 .fadeOut(3000, function() {
2077 $(this).removeClass('wpo_alert_notice');
2078 });
2079 } else {
2080 $form.form_errors.remove('missing-fields');
2081 $('#wp-optimize-logger-settings .save_settings_reminder').slideUp();
2082 }
2083
2084 });
2085
2086 /**
2087 * Validate import field with data-validate attribute.
2088 *
2089 * @param {object} field jquery element
2090 * @param {boolean} required
2091 *
2092 * @return {boolean}
2093 */
2094 function validate_field(field, required) {
2095 var value = field.val(),
2096 validate = field.data('validate');
2097
2098 if (!validate && required) {
2099 return ('' != value.trim());
2100 }
2101
2102 if (validate && !required && '' == value.trim()) {
2103 return true;
2104 }
2105
2106 var valid = true;
2107
2108 switch (validate) {
2109 case 'email':
2110 var regex = /\S+@\S+\.\S+/,
2111 emails = value.split(","),
2112 email = '';
2113
2114 for (var i = 0; i < emails.length; i++) {
2115 email = emails[i].trim();
2116
2117 if ('' == email || !regex.test(email)) {
2118 valid = false;
2119 }
2120 }
2121 break;
2122
2123 case 'url':
2124 // https://gist.github.com/dperini/729294
2125 // @codingStandardsIgnoreLine
2126 var regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
2127
2128 valid = regex.test(value);
2129 break;
2130 }
2131
2132 return valid;
2133 }
2134
2135 /**
2136 * Send check_overdue_crons command and output warning if need.
2137 */
2138 setTimeout(function() {
2139 send_command('check_overdue_crons', null, function (resp) {
2140 if (resp && resp.hasOwnProperty('m')) {
2141 $('#wpo_settings_warnings').append(resp.m);
2142 }
2143 });
2144 }, 11000);
2145
2146 /**
2147 * Hide introduction notice
2148 */
2149 $('#wp-optimize-wrap').on('click', '.wpo-introduction-notice .notice-dismiss, .wpo-introduction-notice .close', function(e) {
2150 $('.wpo-introduction-notice').remove();
2151 send_command('dismiss_install_or_update_notice', null, function (resp) {
2152 if (resp && resp.hasOwnProperty('error')) {
2153 // there was an error.
2154 console.log('There was an error dismissing the install or update notice (dismiss_install_or_update_notice)', resp);
2155 }
2156 });
2157 });
2158
2159 $('#wpo-settings-export').on('click', export_settings);
2160
2161 $('#wpo-settings-import').on('click', function(e) {
2162 e.preventDefault();
2163
2164 block_ui(wpoptimize.importing);
2165
2166 var wpo_import_file_input = document.getElementById('import_settings');
2167 if (0 === wpo_import_file_input.files.length) {
2168 alert(wpoptimize.import_select_file);
2169 $.unblockUI();
2170 return;
2171 }
2172 read_settings_json_file(wpo_import_file_input.files[0]);
2173 });
2174
2175 /**
2176 * Pack WPO settings into a single object
2177 *
2178 * @return {object}
2179 */
2180 function build_settings() {
2181 var date_now = new Date();
2182
2183 return {
2184 epoch_date: date_now.getTime(),
2185 local_date: date_now.toLocaleString(),
2186 network_site_url: wpoptimize.network_site_url,
2187 data: {
2188 cache_settings: wp_optimize.cache_settings(),
2189 minify_settings: wp_optimize.minify_settings(),
2190 smush_settings: wp_optimize.smush_settings(),
2191 database_settings: gather_settings('string')
2192 }
2193 };
2194 }
2195
2196 /**
2197 * Export plugin settings as a JSON file
2198 *
2199 * @param {object} e - Event object
2200 *
2201 * @return {void}
2202 */
2203 function export_settings(e) {
2204 e.preventDefault();
2205
2206 form_data = JSON.stringify(build_settings());
2207
2208 // Attach this data to an anchor on page
2209 var link = document.body.appendChild(document.createElement('a'));
2210 link.setAttribute('download', wpoptimize.export_settings_file_name);
2211 link.setAttribute('style', "display:none;");
2212 link.setAttribute('href', 'data:text/json' + ';charset=UTF-8,' + encodeURIComponent(form_data));
2213 link.click();
2214 }
2215
2216 /**
2217 * Read json settings file and import it
2218 *
2219 * @param {Blob} file - Settings file
2220 *
2221 * @return {void}
2222 */
2223 function read_settings_json_file(file) {
2224 var file_reader = new FileReader();
2225 file_reader.onload = function() {
2226 import_settings(this.result);
2227 };
2228 file_reader.readAsText(file);
2229 }
2230
2231 /**
2232 * Import json data and save it as plugin settings in database
2233 *
2234 * @param {json} json_data
2235 *
2236 * @return {void}
2237 */
2238 function import_settings(json_data) {
2239 var parsed;
2240 try {
2241 parsed = wpo_parse_json(json_data);
2242 } catch (e) {
2243 $.unblockUI();
2244 jQuery('#import_settings').val('');
2245 console.log(json_data);
2246 console.log(e);
2247 alert(wpoptimize.import_invalid_json_file);
2248 return;
2249 }
2250 if (window.confirm(wpoptimize.importing_data_from + ' ' + parsed['network_site_url'] + "\n" + wpoptimize.exported_on + ' ' + parsed['local_date'] + "\n" + wpoptimize.continue_import)) {
2251 // GET the settings back to the AJAX handler
2252 var stringified = JSON.stringify(parsed['data']);
2253 send_command('import_settings', {
2254 settings: stringified
2255 }, function(response) {
2256 $.unblockUI();
2257 if (response && response.errors) {
2258 alert(response.errors.join('<br />'));
2259 } else if (response && response.success) {
2260 alert(response.message);
2261 setTimeout(function() {
2262 window.location.reload();
2263 }, 200);
2264 }
2265 });
2266 } else {
2267 $.unblockUI();
2268 }
2269 }
2270
2271 /**
2272 * Define popup for each optimization action that needs confirmation from user
2273 */
2274 function get_destructive_actions_confirm_popup(action) {
2275 var popups = destructive_actions_confirm_popup = {
2276 postmeta: {
2277 className: 'wpo-confirm',
2278 events: {
2279 'click .wpo-modal--bg': 'close',
2280 'click #confirm_post_meta_deletion': 'deleteConfirm',
2281 'click .cancel': 'cancel',
2282 'click #confirm-post-meta-delete-action': 'confirm'
2283 },
2284 content: function() {
2285 var content_template = wp.template('wpo-postmeta');
2286 return content_template({});
2287 },
2288 deleteConfirm: function() {
2289 var enable_button = $('#confirm_post_meta_deletion').is(':checked');
2290 $('.delete-post-meta').prop('disabled', !enable_button);
2291 }
2292 },
2293 orphandata: {
2294 className: 'wpo-confirm',
2295 events: {
2296 'click .wpo-modal--bg': 'close',
2297 'click #confirm_orphaned_relationship_data_deletion': 'deleteConfirm',
2298 'click .cancel': 'cancel',
2299 'click #confirm-orphaned-relationship-data-delete-action': 'confirm'
2300 },
2301 content: function() {
2302 var content_template = wp.template('wpo-orphandata');
2303 return content_template({});
2304 },
2305 deleteConfirm: function() {
2306 var enable_button = $('#confirm_orphaned_relationship_data_deletion').is(':checked');
2307 $('.delete-orphaned-relationship-data').prop('disabled', !enable_button);
2308 }
2309 },
2310 "grouped-warnings": {
2311 className: 'wpo-confirm',
2312 events: {
2313 'click .wpo-modal--bg': 'close',
2314 'click #confirm_grouped_warnings_data_deletion': 'deleteConfirm',
2315 'click .cancel': 'cancel',
2316 'click #confirm-grouped-warnings-data-delete-action': 'confirm'
2317 },
2318 deleteConfirm: function() {
2319 var enable_button = $('#confirm_grouped_warnings_data_deletion').is(':checked');
2320 $('.delete-grouped-warnings-data').prop('disabled', !enable_button);
2321 }
2322 }
2323 }
2324
2325 return popups[action];
2326 }
2327
2328 /**
2329 * Attach click event to postmeta checkbox
2330 */
2331 function add_warning_for_delete_post_meta_action() {
2332 $('#optimization_button_postmeta_big').on('click', function (evt) {
2333 return function(this_button) {
2334 var remove_post_meta_checkbox = $('#optimization_checkbox_postmeta');
2335
2336 if (should_user_confirm_action('postmeta')) {
2337 wp_optimize.modal.open(
2338 Object.assign(get_destructive_actions_confirm_popup('postmeta'), {
2339 cancel: function() {
2340 $(remove_post_meta_checkbox).prop('checked', false);
2341 },
2342 confirm: function() {
2343 maybe_dismiss_destructive_actions();
2344 this.close();
2345
2346 $(this_button).prop('bypass-confirm-box', true);
2347 $(this_button).trigger('click');
2348
2349 }
2350 }
2351 ));
2352
2353 evt.preventDefault();
2354 return false;
2355 } else {
2356 $(this_button).prop('bypass-confirm-box', false);
2357 return true;
2358 }
2359 }(this);
2360 });
2361 }
2362
2363 /**
2364 * Check if dismiss future confirms checkbox is visible and selected, then save option in DB
2365 */
2366 function maybe_dismiss_destructive_actions() {
2367 var ignores_orphaned_relationship_data_delete_warning_checkbox = $('#ignores_orphaned_relationship_data_deletion_warning');
2368 if (ignores_orphaned_relationship_data_delete_warning_checkbox.is(':visible') && ignores_orphaned_relationship_data_delete_warning_checkbox.is(':checked')) {
2369 send_command('user_ignores_orphaned_relationship_data_deletion_warning', {}, function(response) {
2370 if (response.success) {
2371 wpoptimize.user_always_ignores_orphaned_relationship_data_deletion_warning = '1';
2372 }
2373 });
2374 }
2375
2376 var ignores_post_meta_deletion_warning_checkbox = $('#ignores_post_meta_deletion_warning');
2377 if (ignores_post_meta_deletion_warning_checkbox.is(':visible') && ignores_post_meta_deletion_warning_checkbox.is(':checked')) {
2378 send_command('user_ignores_post_meta_deletion_warning', {}, function(response) {
2379 if (response.success) {
2380 wpoptimize.user_always_ignores_post_meta_deletion_warning = '1';
2381 }
2382 });
2383 }
2384 }
2385
2386 /**
2387 * Check if user dismissed confirms, or should they see the confirm popup
2388 */
2389 function should_user_confirm_action(action) {
2390 if ('orphandata' == action) {
2391 var bypass_confirm = $('#optimization_button_orphandata_big').prop('bypass-confirm-box') == true;
2392
2393 return !bypass_confirm && ('' == wpoptimize.user_always_ignores_orphaned_relationship_data_deletion_warning || '1' !== wpoptimize.user_always_ignores_orphaned_relationship_data_deletion_warning);
2394 } else if ('postmeta' == action) {
2395 var bypass_confirm = $('#optimization_button_postmeta_big').prop('bypass-confirm-box') == true;
2396
2397 return !bypass_confirm && ('' == wpoptimize.user_always_ignores_post_meta_deletion_warning || '1' !== wpoptimize.user_always_ignores_post_meta_deletion_warning);
2398 }
2399 }
2400
2401 /**
2402 * Attach click event to orphandata optimization checkbox
2403 */
2404 function add_warning_for_delete_orphaned_relationship_data_action() {
2405 $('#optimization_button_orphandata_big').on('click', function (evt) {
2406 return function(this_button) {
2407 var remove_orphaned_relationship_data_checkbox = $('#optimization_checkbox_orphandata');
2408
2409 if (should_user_confirm_action('orphandata')) {
2410 wp_optimize.modal.open(
2411 Object.assign(get_destructive_actions_confirm_popup('orphandata'), {
2412 cancel: function() {
2413 $(remove_orphaned_relationship_data_checkbox).prop('checked', false);
2414 },
2415 confirm: function() {
2416 maybe_dismiss_destructive_actions();
2417
2418 this.close();
2419
2420 $(this_button).prop('bypass-confirm-box', true);
2421 $(this_button).trigger('click');
2422 }
2423 }
2424 ));
2425
2426 evt.preventDefault();
2427 return false;
2428 } else {
2429 $(this_button).prop('bypass-confirm-box', false);
2430 return true;
2431 }
2432 }(this);
2433 });
2434 }
2435
2436 // Attach heartbeat API events
2437 heartbeat.setup();
2438
2439 return {
2440 send_command: send_command,
2441 optimization_get_info: optimization_get_info,
2442 take_a_backup_with_updraftplus: take_a_backup_with_updraftplus,
2443 save_auto_backup_options: save_auto_backup_options,
2444 build_settings: build_settings
2445 }
2446 }; // END function WP_Optimize()
2447
2448 /**
2449 * Init Select2 Library
2450 */
2451 var WPO_Select2 = function () {
2452 if ('function' === typeof jQuery.fn.select2) {
2453 jQuery(".wpo-select2").not('.select2-hidden-accessible').select2();
2454 }
2455 }
2456
2457 /**
2458 * Init Tooltip Library
2459 */
2460 var WPO_Tooltip = function () {
2461 if ('function' === typeof jQuery.fn.tooltip) {
2462 jQuery(".wpo-tooltip").tooltip({
2463 items: "[data-tooltip]",
2464 content: function() {
2465 return jQuery('<span>').text(jQuery(this).attr("data-tooltip"));
2466 },
2467 position: {
2468 my: "center bottom",
2469 at: "center top",
2470 collision: "flipfit"
2471 },
2472 open: function(event, ui) {
2473 jQuery(".wpo-tooltip").not(this).tooltip("close");
2474 }
2475 });
2476
2477 // New: explicit outside-tap/click close, since jQuery UI has no touch equivalent of mouseleave/focusout
2478 jQuery(document).on("touchstart click", function(e) {
2479 if (!jQuery(e.target).closest("[data-tooltip], .ui-tooltip").length) {
2480 jQuery(".wpo-tooltip").each(function() {
2481 var $el = jQuery(this);
2482 if ($el.data("ui-tooltip")) {
2483 $el.tooltip("close");
2484 }
2485 });
2486 }
2487 });
2488 }
2489 }
2490
2491 jQuery(function ($) {
2492
2493 WPO_Tooltip();
2494
2495 WPO_Select2();
2496
2497 /**
2498 * Show additional options section if optimization enabled
2499 *
2500 * @param {string} checkbox Logger settings jQuery checkbox object.
2501 *
2502 * @return {void}
2503 */
2504 function show_hide_additional_logger_options($checkbox) {
2505 var additional_section_id = ['#', $checkbox.data('additional')].join('');
2506
2507 if ($checkbox.is(':checked')) {
2508 $(additional_section_id).show();
2509 } else {
2510 $(additional_section_id).hide();
2511 }
2512 }
2513
2514 // Add events handler for each logger.
2515 $('.wp-optimize-logging-settings').each(function () {
2516 var $checkbox = $(this);
2517 show_hide_additional_logger_options($checkbox);
2518 $checkbox.on('change', function () {
2519 show_hide_additional_logger_options($checkbox);
2520 });
2521 });
2522
2523 var add_logging_btn = $('#settings_form');
2524
2525 /**
2526 * Handle add logging destination click.
2527 */
2528 add_logging_btn.on('click', '#wpo_add_logger_link', function(e) {
2529 e.preventDefault();
2530 $('#wp-optimize-logger-settings .save_settings_reminder').after(get_add_logging_form_html());
2531
2532 filter_select_destinations($('.wpo_logger_type').first());
2533
2534 WPO_Select2();
2535 });
2536
2537 /**
2538 * Handle logging destination select change.
2539 */
2540 $('#wp-optimize-general-settings').on('change', '.wpo_logger_type', function() {
2541 var select = $(this),
2542 logger_id = select.val(),
2543 options_container = select.parent().find('.wpo_additional_logger_options');
2544
2545 options_container.html(get_logging_additional_options_html(logger_id));
2546
2547 if (select.val()) {
2548 show_logging_save_settings_reminder();
2549 }
2550 });
2551
2552 /**
2553 * Show save settings reminder for logging settings.
2554 *
2555 * @return {void}
2556 */
2557 function show_logging_save_settings_reminder() {
2558 var reminder = $('#wp-optimize-logger-settings .save_settings_reminder');
2559
2560 if (!reminder.is(':visible')) {
2561 reminder.slideDown('normal');
2562 }
2563 }
2564
2565 /**
2566 * Handle edit logger click.
2567 */
2568 $('#settings_form').on('click', '.wpo_logging_actions_row .wpo_edit_logger', function() {
2569
2570 var link = $(this),
2571 container = link.closest('.wpo_logging_row');
2572
2573 $('.wpo_additional_logger_options', container).removeClass('wpo_hidden');
2574 $('.wpo_logging_options_row', container).hide();
2575 $('.wpo_logging_status_row', container).hide();
2576 /*link.hide();
2577 link.next('.wpo_delete_logger').hide();*/
2578 link.parent('.wpo_logging_actions_row').hide();
2579 $(container).children('.wpo_logging_edit_row').show();
2580
2581 return false;
2582 });
2583
2584 /**
2585 * Handle cancel logger click.
2586 */
2587 $('#settings_form').on('click', '.wpo_logging_edit_row .wpo_cancel_logging', function() {
2588
2589 var cancel_btn = $(this),
2590 container = cancel_btn.closest('.wpo_logging_row');
2591
2592 $(container).children('.wpo_logging_edit_row').hide();
2593 $(container).children('.wpo_logging_options_row').show();
2594 $(container).children('.wpo_logging_status_row').show();
2595 $(container).children('.wpo_logging_actions_row').show();
2596 $(container).children('.wpo_additional_logger_options').addClass('wpo_hidden');
2597
2598 return false;
2599 });
2600
2601 $('#wp-optimize-logger-settings').on('change', '.wpo_logger_addition_option', function() {
2602 show_logging_save_settings_reminder();
2603 });
2604
2605 /**
2606 * Handle change of active/inactive status and update hidden field value.
2607 */
2608 $('#settings_form').on('change', '.wpo_logger_active_checkbox', function() {
2609 var checkbox = $(this),
2610 hidden_input = checkbox.closest('label').find('input[type="hidden"]');
2611
2612 hidden_input.val(checkbox.is(':checked') ? '1' : '0');
2613 });
2614
2615 /**
2616 * Handle delete logger destination click.
2617 */
2618 $('#wp-optimize-general-settings').on('click', '.wpo_delete_logger', function() {
2619
2620 if (!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination)) {
2621 return false;
2622 }
2623
2624 var btn = $(this);
2625 btn.closest('.wpo_logging_row, .wpo_add_logger_form').remove();
2626 filter_all_select_destinations();
2627
2628 if (0 == $('#wp-optimize-logging-options .wpo_logging_row').length) {
2629 $('#wp-optimize-logging-options').hide();
2630 }
2631
2632 setTimeout(function(){
2633 $('#wp-optimize-save-main-settings').trigger('click');
2634 }, 500);
2635
2636 return false;
2637 });
2638
2639 /**
2640 * Filter all selects with logger destinations, called after some destination deleted.
2641 *
2642 * @return {void}
2643 */
2644 function filter_all_select_destinations() {
2645 $('.wpo_logger_type').each(function() {
2646 filter_select_destinations($(this));
2647 });
2648 }
2649
2650 /**
2651 * Filter certain select options depending on currently selected values.
2652 *
2653 * @param {object} select
2654 *
2655 * @return {void}
2656 */
2657 function filter_select_destinations(select) {
2658 var i,
2659 destination,
2660 current_destinations = get_current_destinations();
2661
2662 for (i in current_destinations) {
2663 destination = current_destinations[i];
2664 if (wpoptimize.loggers_classes_info[destination].allow_multiple) {
2665 $('option[value="'+destination+'"]', select).show();
2666 } else {
2667 $('option[value="'+destination+'"]', select).hide();
2668 }
2669 }
2670 }
2671
2672 /**
2673 * Returns currently selected loggers destinations.
2674 *
2675 * @return {Array}
2676 */
2677 function get_current_destinations() {
2678 var destinations = [];
2679
2680 $('.wpo_logging_row, .wpo_logger_type').each(function() {
2681 var destination = $(this).is('select') ? $(this).val() : $(this).data('id');
2682
2683 if (destination) destinations.push(destination);
2684 });
2685
2686 return destinations;
2687 }
2688
2689 /**
2690 * Return add logging form.
2691 *
2692 * @return {string}
2693 */
2694 function get_add_logging_form_html() {
2695 var i,
2696 select_options = [
2697 '<option value="">' + wpoptimize.select_destination + '</option>'
2698 ];
2699
2700 for (i in wpoptimize.loggers_classes_info) {
2701 if (!wpoptimize.loggers_classes_info.hasOwnProperty(i)) continue;
2702
2703 if (!wpoptimize.loggers_classes_info[i].available) continue;
2704
2705 select_options.push(['<option value="',i,'">',wpoptimize.loggers_classes_info[i].description,'</option>'].join(''));
2706 }
2707
2708 return [
2709 '<div class="wpo_add_logger_form">',
2710 '<select class="wpo_logger_type wpo-select2" name="wpo-logger-type[]">',
2711 select_options.join(''),
2712 '</select>',
2713 '<div class="wpo_logging_edit_row" style="display:block;"><span class="wpo_delete_logger button button-secondary" title="'+wpoptimize.cancel+'">'+wpoptimize.cancel+'</span>',
2714 '<span class="wpo_save_logging button button-primary" title="'+wpoptimize.add+'">'+wpoptimize.add+'</span></div>',
2715 '<div class="wpo_additional_logger_options"></div>',
2716 '</div>'
2717 ].join('');
2718 }
2719
2720 /**
2721 * Returns logging options html.
2722 *
2723 * @param {string} logger_id
2724 *
2725 * @return {string}
2726 */
2727 function get_logging_additional_options_html(logger_id) {
2728 if (!wpoptimize.loggers_classes_info[logger_id].options) return '';
2729
2730 var i,
2731 options = wpoptimize.loggers_classes_info[logger_id].options,
2732 options_list = [],
2733 placeholder = '',
2734 validate = '';
2735
2736 for (i in options) {
2737 if (!options.hasOwnProperty(i)) continue;
2738
2739 if (Array.isArray(options[i])) {
2740 placeholder = options[i][0].trim();
2741 validate = options[i][1].trim();
2742 } else {
2743 placeholder = options[i].trim();
2744 validate = '';
2745 }
2746
2747 options_list.push([
2748 '<input class="wpo_logger_addition_option" type="text" name="wpo-logger-options[',i,'][]" value="" ',
2749 'placeholder="',placeholder,'" ',('' !== validate ? 'data-validate="'+validate+'"' : ''), '/>'
2750 ].join(''));
2751 }
2752
2753 // Add hidden field for active/inactive value.
2754 options_list.push('<input type="hidden" name="wpo-logger-options[active][]" value="1" />');
2755
2756 return options_list.join('');
2757 }
2758
2759 /**
2760 * Layout - Adds `is-scrolled` class to the body element when scrolled.
2761 */
2762 var is_scrolled = false;
2763 $(window).on('scroll', function(e) {
2764 window.requestAnimationFrame(function() {
2765 var threshold = $('.wpo-main-header').length ? $('.wpo-main-header')[0].offsetTop : 0;
2766 if ((window.pageYOffset > threshold - 20) != is_scrolled) {
2767 is_scrolled = !is_scrolled;
2768 $('body').toggleClass('is-scrolled', is_scrolled);
2769 }
2770 });
2771 });
2772
2773 // Opens the video preview / info popup
2774 $('.wpo-info__trigger').on('click', function(e) {
2775 e.preventDefault();
2776 var $container = $(this).closest('.wpo-info');
2777 $container.toggleClass('opened');
2778 });
2779
2780 // Embed videos when clicking the vimeo links
2781 $('.wpo-video-preview a').on('click', function(e) {
2782 var video_url = $(this).data('embed');
2783 if (video_url) {
2784 e.preventDefault();
2785 var $iframe = $('<iframe width="356" height="200" allowfullscreen webkitallowfullscreen mozallowfullscreen>').attr('src', video_url);
2786 $iframe.insertAfter($(this));
2787 $(this).remove();
2788 $iframe.focus();
2789 }
2790 });
2791
2792 // Show/hide Enable the caching menu in the admin bar on cache/minify status change
2793 $(document).on('wp-optimize/cache/toggle-status wp-optimize/minify/toggle-status', function() {
2794 var minify_or_cache_enabled = $('#wpo_min_enable_minify').prop('checked') || $('#enable_page_caching').prop('checked');
2795 $('#enable_cache_in_admin_bar_option').toggleClass('wpo_hidden', !minify_or_cache_enabled);
2796 });
2797 });
2798