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
← All changes | js/wpoadmin.js +845 -170 3.2.3 → 4.7.0 View file →
@@ -43,18 +43,44 @@
43 43 var WP_Optimize = function () {
44 44 var $ = jQuery;
45 45 var debug_level = 0;
46 46 var queue = new Updraft_Queue();
47 + var block_ui = wp_optimize.block_ui;
47 48 var send_command = wp_optimize.send_command;
48 49 var optimization_force = false;
49 50 var optimization_logged_warnings = false;
50 51 var force_single_table_optimization = false;
51 -
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 +
52 78 /*
53 79 * Enable select all checkbox for optimizations list.
54 80 */
55 81 define_select_all_checkbox($('#select_all_optimizations'), $('#optimizations_list .optimization_checkbox'));
56 -
82 +
57 83 /**
58 84 * Either display normally, or grey-out, the scheduling options, depending on whether any schedule has been selected.
59 85 *
60 86 * @return {string}
@@ -75,28 +101,8 @@
75 101 $('#enable-schedule').on('change', function () {
76 102 enable_or_disable_schedule_options();
77 103 });
78 104
79 - // table sorter library.
80 - // This calls the tablesorter library in order to sort the table information correctly.
81 - // There is a fix below on line 172 to apply applyWidgets on load to avoid diplay hidden for tabs.
82 - // add parser through the tablesorter addParser method
83 - $.tablesorter.addParser({
84 - // set a unique id
85 - id: 'sizes',
86 - is: function(s) {
87 - // return false so this parser is not auto detected
88 - return false;
89 - },
90 - format: function(cell_content, table, cell) {
91 - var val = $(cell).data('raw_value');
92 - if (!val) val = 0;
93 - return parseInt(val);
94 - },
95 - // set type, either numeric or text
96 - type: 'numeric'
97 - });
98 -
99 105 /*
100 106 * Triggered when the database tabs are loaded.
101 107 */
102 108
@@ -104,52 +110,46 @@
104 110 /*
105 111 * Setup table events and tablesorter
106 112 */
107 113
108 - var table_list_filter = $('#wpoptimize_table_list_filter'),
109 - table_list = $('#wpoptimize_table_list'),
110 - table_footer_line = $('#wpoptimize_table_list tbody:last'),
111 - tables_not_found = $('#wpoptimize_table_list_tables_not_found');
114 + var elTable = document.getElementById('wpoptimize_table_list');
112 115
113 - table_list.tablesorter({
114 - theme: 'default',
115 - widgets: ['zebra', 'rows', 'filter'],
116 - cssInfoBlock: "tablesorter-no-sort",
117 - // This option is to specify with colums will be disabled for sorting
118 - headers: {
119 - 2: {sorter: 'digit'},
120 - 3: {sorter: 'sizes'},
121 - 4: {sorter: 'sizes'},
122 - // For Column Action
123 - 7: {sorter: false }
124 - },
125 - widgetOptions: {
126 - // filter_anyMatch replaced! Instead use the filter_external option
127 - // Set to use a jQuery selector (or jQuery object) pointing to the
128 - // external filter (column specific or any match)
129 - filter_external: table_list_filter,
130 - // add a default type search to the second table column
131 - filter_defaultFilter: { 2 : '~{query}' }
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 + }
132 139 }
133 - });
134 140
135 - /*
136 - * After tables filtered check if we need show table footer and No tables message.
137 - */
138 - table_list.on('filterEnd', function() {
139 - var search_value = $.trim(table_list_filter.val());
140 -
141 - if ('' == search_value) {
142 - table_footer_line.show();
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';
143 148 } else {
144 - table_footer_line.hide();
149 + tables_not_found.style.display = 'none';
145 150 }
146 -
147 - if (0 == $('#the-list tr:visible', table_list).length) {
148 - tables_not_found.show();
149 - } else {
150 - tables_not_found.hide();
151 - }
151 +
152 152 });
153 153
154 154 /*
155 155 * Setup force optimization checkboxes and associated events
@@ -185,8 +185,12 @@
185 185
186 186 // Update single table optimization buttons state on load.
187 187 update_single_table_optimization_buttons(force_single_table_optimization);
188 188
189 + // Attach warning events
190 + add_warning_for_delete_post_meta_action();
191 + add_warning_for_delete_orphaned_relationship_data_action();
192 +
189 193 });
190 194
191 195 /**
192 196 * Temporarily show a dashboard notice, and then remove it. The HTML will be prepended to the .wrap.wp-optimize-wrap element.
@@ -271,16 +275,14 @@
271 275
272 276 });
273 277
274 278 $('#wp-optimize-wrap').on('page-change', function(e, params) {
275 - // When changing the page, trigger a click, in case the page was loaded somewhere else.
276 - if ('WP-Optimize' == params.page && $('#wp-optimize-nav-tab-WP-Optimize-optimize').is('.nav-tab-active')) {
277 - $('#wp-optimize-nav-tab-WP-Optimize-optimize').trigger('click');
278 - }
279 279 // Trigger the global tab change events when changing page
280 280 var active_tab = $('.wpo-page[data-whichpage='+params.page+']').find('.nav-tab-wrapper .nav-tab-active');
281 281 $('#wp-optimize-wrap').trigger('tab-change', { page: params.page, tab: active_tab.data('tab') });
282 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'));
283 285 });
284 286
285 287 // set a time out, as needs to be done once the rest is loaded
286 288 setTimeout(function() {
@@ -298,9 +300,9 @@
298 300 if (!clicked_tab_id) { return; }
299 301
300 302 toggle_mobile_menu(false);
301 303 // Mobile menu TABS toggle
302 - if ($(this).is('[role="toggle-menu"]')) {
304 + if ($(this).is('[id^="wp-optimize-nav-tab-menu-"]')) {
303 305 toggle_mobile_menu(true);
304 306 return;
305 307 }
306 308
@@ -356,24 +358,27 @@
356 358 $('#wp-optimize-wrap').removeClass('wpo-mobile-menu-opened');
357 359 }
358 360 }
359 361
362 + var database_tabs_loading = false;
360 363 var database_tabs_loaded = false;
361 364 // When showing the tables tab
362 - $('#wp-optimize-wrap').on('tab-change/WP-Optimize/tables', function(e) {
365 + $('#wp-optimize-wrap').on('tab-change/wpo_database/tables', function(e) {
363 366 get_database_tabs();
364 367 });
365 368
366 - // When showing the tables tab
367 - $('#wp-optimize-wrap').on('tab-change/WP-Optimize/optimize', function(event, data) {
369 + // When showing the optimizations tab
370 + $('#wp-optimize-wrap').on('tab-change/wpo_database/optimize', function(event, data) {
368 371 get_database_tabs();
369 372 });
370 373
374 +
371 375 // When showing the settings tab
372 376 $('#wp-optimize-wrap').on('tab-change/wpo_settings/settings', function(event, data) {
373 377 // If the innodb_force_optimize--container is present, fetch the required data.
374 378 // We load the database tabs together, as they need the same processing.
375 379 if (data.content.find('.innodb_force_optimize--container').length) get_database_tabs();
380 + WPO_Status_Report();
376 381 });
377 382
378 383 /**
379 384 * Get the data for the database tabs. We get them at the same time, as they both need the same time consuming requests.
@@ -378,27 +383,84 @@
378 383 /**
379 384 * Get the data for the database tabs. We get them at the same time, as they both need the same time consuming requests.
380 385 */
381 386 function get_database_tabs() {
382 - if (database_tabs_loaded) return;
383 - var container = $('.wpo-page[data-whichpage=WP-Optimize]');
387 + if (database_tabs_loading || database_tabs_loaded) return;
388 + var container = $('.wpo-page[data-whichpage=wpo_database]');
384 389 var shade = container.find('.wpo_shade');
385 390 shade.removeClass('hidden');
391 + database_tabs_loading = true;
386 392 send_command('get_database_tabs', {}, function(response) {
387 - // Set the satus to true, to prevent loading again.
393 + // Set the status to true, to prevent loading again.
388 394 database_tabs_loaded = true;
389 395
390 - // Updtate the optimizations tab
396 + // Update the optimizations tab
391 397 if (response.hasOwnProperty('optimizations')) {
392 398 container.find('.wp-optimize-optimizations-table-placeholder').replaceWith(response.optimizations);
393 399 }
394 400
395 - // Updtate the optimizations tables list
396 - update_tables_list(response);
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 + }
397 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 +
398 459 $(document).trigger('wpo_database_tabs_loaded');
399 460
400 461 }).always(function() {
462 + database_tabs_loading = false;
401 463 shade.addClass('hidden');
402 464 });
403 465 }
404 466
@@ -411,18 +473,18 @@
411 473 */
412 474 function gather_settings(output_format) {
413 475 var form_data = '',
414 476 output_format = ('undefined' === typeof output_format) ? 'string' : output_format,
415 - $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-']");
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]");
416 478
417 479 if ('object' == output_format) {
418 480 form_data = $form_elements.serializeJSON({useIntKeysAsArrayIndex: true});
419 481 } else {
420 - // Excluding the unnecessary 'action' input avoids triggering a very mis-conceived mod_security rule seen on one user's site.
482 + // Excluding the unnecessary 'action' input avoids triggering a very misconceived mod_security rule seen on one user's site.
421 483 form_data = $form_elements.serialize();
422 484
423 485 // Include unchecked checkboxes. user filter to only include unchecked boxes.
424 - $.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-"]')
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]')
425 487 .filter(function (idx) {
426 488 return $(this).prop('checked') == false
427 489 }),
428 490 function (idx, el) {
@@ -447,9 +509,9 @@
447 509 optimization_logged_warnings = false;
448 510 }
449 511
450 512 /**
451 - * Proceses the queue
513 + * Processes the queue
452 514 *
453 515 * @return void
454 516 */
455 517 function process_queue() {
@@ -564,20 +626,20 @@
564 626 if (response.hasOwnProperty('total_size')) {
565 627 $('#optimize_current_db_size').html(response.total_size);
566 628 }
567 629
568 - // Status check if optimizing tables.
569 - if (id == 'optimizetables' && data.optimization_table) {
570 - if (queue.is_empty()) {
571 - $('#optimization_spinner_' + id).hide();
572 - $('#optimization_checkbox_' + id).show();
573 - $('.optimization_button_' + id).prop('disabled', false);
574 -
575 - $('#optimization_info_' + id).html(wpoptimize.optimization_complete + (optimization_logged_warnings ? (' ' + wpoptimize.with_warnings) : ''));
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);
576 637 } else {
577 - $('#optimization_checkbox_' + id).hide();
578 - $('#optimization_spinner_' + id).show();
579 - $('.optimization_button_' + id).prop('disabled', true);
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) : ''));
580 642 }
581 643 }
582 644
583 645 // check if we need update unapproved comments count.
@@ -696,22 +758,22 @@
696 758 no_queue_actions_added = false;
697 759 }
698 760 }
699 761 });
700 - } else if (additional_data_length > 0) {
762 + } else {
701 763 // check if additional data passed for optimization.
702 764 data = {
703 765 optimization_id: id
704 766 };
705 767
706 - for (var i in additional_data) {
707 - if (!additional_data.hasOwnProperty(i)) continue;
708 - data[i] = additional_data[i];
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 + }
709 773 }
710 774
711 775 queue.enqueue(data);
712 - } else {
713 - queue.enqueue(id);
714 776 }
715 777
716 778 // if new actions was not added in tasks queue then we don't process queue.
717 779 if (no_queue_actions_added) return;
@@ -767,9 +829,9 @@
767 829
768 830 /*
769 831 * Run single optimization click.
770 832 */
771 - $('#wp-optimize-nav-tab-WP-Optimize-optimize-contents').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
833 + $('#wp-optimize-nav-tab-wpo_database-optimize-contents').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
772 834 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
773 835 if (!optimization_id) {
774 836 console.log("Optimization ID corresponding to pressed button not found");
775 837 return;
@@ -787,22 +849,247 @@
787 849
788 850 /*
789 851 * Run all optimizations click.
790 852 */
791 - $('#wp-optimize-nav-tab-WP-Optimize-optimize-contents').on('click', '#wp-optimize', function (e) {
792 - var run_btn = $(this);
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 + }
793 859
794 - e.preventDefault();
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 + });
795 871
796 - // disable run button to avoid double click.
797 - run_btn.prop('disabled', true);
798 - save_sites_list_and_do_action(function() {
799 - run_btn.prop('disabled', false);
800 - run_optimizations();
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 + }
801 892 });
802 - });
893 +
894 + user_confirm_destructive_actions_grouped(confirmations_stack, callback);
895 + }
803 896
804 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 + /**
805 1092 * Sent command to run selected optimizations and auto backup if selected
806 1093 *
807 1094 * @return void
808 1095 */
@@ -885,16 +1172,15 @@
885 1172 wpo_settings_all_sites_checkbox,
886 1173 wpo_settings_sites_list_items
887 1174 );
888 1175
889 - var sites_list_clicked_count = 0;
1176 + var debounceTimer;
890 1177
891 1178 $([wpo_settings_all_sites_checkbox, wpo_settings_sites_list_items]).each(function() {
892 1179 $(this).on('change', function() {
893 - sites_list_clicked_count++;
894 - setTimeout(function() {
895 - sites_list_clicked_count--;
896 - if (sites_list_clicked_count == 0) update_optimizations_info();
1180 + clearTimeout(debounceTimer);
1181 + debounceTimer = setTimeout(function() {
1182 + update_optimizations_info();
897 1183 }, 1000);
898 1184 });
899 1185 });
900 1186
@@ -998,27 +1284,20 @@
998 1284 *
999 1285 * @return {[type]} optimizations
1000 1286 */
1001 1287 function run_optimization() {
1002 - $optimizations = $('#optimizations_list .optimization_checkbox:checked');
1288 + var optimizations = $('#optimizations_list .optimization_checkbox:checked').toArray();
1003 1289
1004 - $optimizations.sort(function (a, b) {
1005 - // Convert to IDs.
1006 - a = $(a).closest('.wp-optimize-settings').data('optimization_run_sort_order');
1007 - b = $(b).closest('.wp-optimize-settings').data('optimization_run_sort_order');
1008 - if (a > b) {
1009 - return 1;
1010 - } else if (a < b) {
1011 - return -1;
1012 - } else {
1013 - return 0;
1014 - }
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
1015 1294 });
1016 1295
1017 1296 var optimization_options = {};
1018 1297
1019 - $optimizations.each(function (index) {
1020 - var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
1298 + sorted_optimizations.forEach(function (element) {
1299 + var optimization_id = $(element).closest('.wp-optimize-settings').data('optimization_id');
1021 1300 if (!optimization_id) {
1022 1301 console.log("Optimization ID corresponding to pressed button not found");
1023 1302 return;
1024 1303 }
@@ -1044,8 +1323,9 @@
1044 1323 };
1045 1324
1046 1325 // update body with new content.
1047 1326 $("#wpoptimize_table_list tbody").remove();
1327 + $("#wpoptimize_table_list tfoot").remove();
1048 1328 $("#wpoptimize_table_list thead").after(response.table_list);
1049 1329
1050 1330 $("#wpoptimize_table_list").trigger("updateAll", [resort, callback]);
1051 1331 }
@@ -1063,8 +1343,14 @@
1063 1343 }
1064 1344
1065 1345 $('#wp_optimize_table_list_refresh').on('click', function (e) {
1066 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 + }
1067 1353 var shade = $(this).closest('.wpo-tab-postbox').find('.wpo_shade');
1068 1354 shade.removeClass('hidden');
1069 1355 $('#wpoptimize_table_list tbody').css('opacity', '0.5');
1070 1356 send_command('get_table_list', {refresh_plugin_json: true}, update_tables_list).always(function() {
@@ -1071,10 +1357,26 @@
1071 1357 shade.addClass('hidden');
1072 1358 });
1073 1359 });
1074 1360
1075 - $('#database_settings_form, #settings_form').on('click', '.wpo-save-settings', function (e) {
1361 + $('#wpo-404-detector-form').on('click', '#wpo-404-clear-logs', function (e) {
1076 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();
1077 1379 var form = $(this).closest('form');
1078 1380 var spinner = form.find('.wpo-saving-settings');
1079 1381 var form_data = gather_settings();
1080 1382
@@ -1082,8 +1384,9 @@
1082 1384
1083 1385 if (form.form_errors.has_errors()) return;
1084 1386
1085 1387 spinner.show();
1388 + block_ui(wpoptimize.saving);
1086 1389
1087 1390 // when optimizations list in the document - send information about selected optimizations.
1088 1391 if ($('#optimizations_list').length) {
1089 1392 $('#optimizations_list .optimization_checkbox:checked').each(function() {
@@ -1120,8 +1423,23 @@
1120 1423 if (resp && resp.hasOwnProperty('optimizations_table')) {
1121 1424 $('#optimizations_list').replaceWith(resp.optimizations_table);
1122 1425 }
1123 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 +
1124 1442 // Need to refresh the page if enable-admin-menu tick state has changed.
1125 1443 if (resp.save_results.refresh) {
1126 1444 location.reload();
1127 1445 }
@@ -1126,11 +1444,24 @@
1126 1444 location.reload();
1127 1445 }
1128 1446 }).always(function() {
1129 1447 spinner.hide();
1448 + $.unblockUI();
1130 1449 });
1131 1450 });
1132 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 +
1133 1464 /*
1134 1465 * Handle Wipe Settings click.
1135 1466 */
1136 1467 $('#settings_form').on('click', '.wpo-wipe-settings', function() {
@@ -1209,8 +1540,9 @@
1209 1540 btn.prop('disabled', false);
1210 1541 spinner.addClass('visibility-hidden');
1211 1542 action_done_icon.show().removeClass('visibility-hidden').delay(2500).fadeOut('fast', function() {
1212 1543 btn.show();
1544 + action_done_icon.show().addClass('visibility-hidden');
1213 1545 });
1214 1546 });
1215 1547 }
1216 1548
@@ -1283,9 +1615,9 @@
1283 1615 for (i in response) {
1284 1616 if (!response.hasOwnProperty(i)) continue;
1285 1617
1286 1618 dom_id = ['#wp-optimize-settings-', response[i].dom_id].join('');
1287 - info = response[i].info ? response[i].info.join('<br>') : '';
1619 + info = response[i].info ? response[i].info : '';
1288 1620
1289 1621 $(dom_id + ' .wp-optimize-settings-optimization-info').html(info);
1290 1622 }
1291 1623 }
@@ -1440,25 +1772,8 @@
1440 1772 }
1441 1773 });
1442 1774 };
1443 1775
1444 - /*
1445 - * Handle ajax information for optimizations.
1446 - *
1447 - * @return void
1448 - */
1449 - jQuery(function() {
1450 - $('.wp-optimize-optimization-info-ajax').each(function () {
1451 - var optimization_info = $(this),
1452 - optimization_info_container = optimization_info.parent(),
1453 - optimization_id = optimization_info.data('id');
1454 -
1455 - // trigger event about optimization get info action started.
1456 - $(document).trigger(['optimization_get_info_', optimization_id, '_start'].join(''));
1457 - optimization_get_info(optimization_info_container, optimization_id, {support_ajax_get_info: true});
1458 - });
1459 - });
1460 -
1461 1776 // attach event handlers after database tables template loaded.
1462 1777 // Handle single optimization click.
1463 1778 $('#wpoptimize_table_list').on('click', '.run-single-table-optimization', function () {
1464 1779 var take_backup_checkbox = $('#enable-auto-backup-1'),
@@ -1535,9 +1850,9 @@
1535 1850 // Handle delete table click
1536 1851 $('#wpoptimize_table_list').on('click', '.run-single-table-delete', function () {
1537 1852 table_to_remove_btn = $(this);
1538 1853 var take_backup_checkbox = $('#enable-auto-backup-1');
1539 - if ('' == wpoptimize.user_always_ignores_table_delete_warning || '1' !== wpoptimize.user_always_ignores_table_delete_warning) {
1854 + if ('' == wpoptimize.user_always_ignores_table_deletion_warning || '1' !== wpoptimize.user_always_ignores_table_deletion_warning) {
1540 1855 wp_optimize.modal.open({
1541 1856 className: 'wpo-confirm',
1542 1857 events: {
1543 1858 'click .wpo-modal--bg': 'close',
@@ -1568,13 +1883,13 @@
1568 1883 this.$('.delete-table').prop('disabled', !enable_button);
1569 1884 },
1570 1885 deleteTable: function() {
1571 1886 // check if user ignore table warning
1572 - var ignores_table_detele_warning_checkbox = this.$('#ignores_table_delete_warning');
1573 - if (ignores_table_detele_warning_checkbox.is(':checked')) {
1574 - send_command('user_ignores_table_delete_warning', {}, function(response) {
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) {
1575 1890 if (response.success) {
1576 - wpoptimize.user_always_ignores_table_delete_warning = '1';
1891 + wpoptimize.user_always_ignores_table_deletion_warning = '1';
1577 1892 }
1578 1893 });
1579 1894 }
1580 1895 // check if backup checkbox is checked for db tables
@@ -1655,9 +1970,9 @@
1655 1970
1656 1971
1657 1972
1658 1973 /**
1659 - * Send ajax commant to remove single database table.
1974 + * Send ajax command to remove single database table.
1660 1975 *
1661 1976 * @param {Object} btn jQuery object of clicked "Remove" button.
1662 1977 *
1663 1978 * @return void
@@ -1780,12 +2095,12 @@
1780 2095 var value = field.val(),
1781 2096 validate = field.data('validate');
1782 2097
1783 2098 if (!validate && required) {
1784 - return ('' != $.trim(value));
2099 + return ('' != value.trim());
1785 2100 }
1786 2101
1787 - if (validate && !required && '' == $.trim(value)) {
2102 + if (validate && !required && '' == value.trim()) {
1788 2103 return true;
1789 2104 }
1790 2105
1791 2106 var valid = true;
@@ -1796,9 +2111,9 @@
1796 2111 emails = value.split(","),
1797 2112 email = '';
1798 2113
1799 2114 for (var i = 0; i < emails.length; i++) {
1800 - email = $.trim(emails[i]);
2115 + email = emails[i].trim();
1801 2116
1802 2117 if ('' == email || !regex.test(email)) {
1803 2118 valid = false;
1804 2119 }
@@ -1830,9 +2145,9 @@
1830 2145
1831 2146 /**
1832 2147 * Hide introduction notice
1833 2148 */
1834 - $('.wpo-introduction-notice .notice-dismiss, .wpo-introduction-notice .close').on('click', function(e) {
2149 + $('#wp-optimize-wrap').on('click', '.wpo-introduction-notice .notice-dismiss, .wpo-introduction-notice .close', function(e) {
1835 2150 $('.wpo-introduction-notice').remove();
1836 2151 send_command('dismiss_install_or_update_notice', null, function (resp) {
1837 2152 if (resp && resp.hasOwnProperty('error')) {
1838 2153 // there was an error.
@@ -1840,17 +2155,346 @@
1840 2155 }
1841 2156 });
1842 2157 });
1843 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 +
1844 2439 return {
1845 2440 send_command: send_command,
1846 2441 optimization_get_info: optimization_get_info,
1847 2442 take_a_backup_with_updraftplus: take_a_backup_with_updraftplus,
1848 - save_auto_backup_options: save_auto_backup_options
2443 + save_auto_backup_options: save_auto_backup_options,
2444 + build_settings: build_settings
1849 2445 }
1850 2446 }; // END function WP_Optimize()
1851 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 +
1852 2491 jQuery(function ($) {
2492 +
2493 + WPO_Tooltip();
2494 +
2495 + WPO_Select2();
2496 +
1853 2497 /**
1854 2498 * Show additional options section if optimization enabled
1855 2499 *
1856 2500 * @param {string} checkbox Logger settings jQuery checkbox object.
@@ -1875,18 +2519,20 @@
1875 2519 show_hide_additional_logger_options($checkbox);
1876 2520 });
1877 2521 });
1878 2522
1879 - var add_logging_btn = $('#wpo_add_logger_link');
2523 + var add_logging_btn = $('#settings_form');
1880 2524
1881 2525 /**
1882 2526 * Handle add logging destination click.
1883 2527 */
1884 - add_logging_btn.on('click', function(e) {
2528 + add_logging_btn.on('click', '#wpo_add_logger_link', function(e) {
1885 2529 e.preventDefault();
1886 2530 $('#wp-optimize-logger-settings .save_settings_reminder').after(get_add_logging_form_html());
1887 2531
1888 2532 filter_select_destinations($('.wpo_logger_type').first());
2533 +
2534 + WPO_Select2();
1889 2535 });
1890 2536
1891 2537 /**
1892 2538 * Handle logging destination select change.
@@ -1918,21 +2564,41 @@
1918 2564
1919 2565 /**
1920 2566 * Handle edit logger click.
1921 2567 */
1922 - $('.wpo_logging_actions_row .dashicons-edit').on('click', function() {
2568 + $('#settings_form').on('click', '.wpo_logging_actions_row .wpo_edit_logger', function() {
1923 2569
1924 2570 var link = $(this),
1925 2571 container = link.closest('.wpo_logging_row');
1926 2572
1927 2573 $('.wpo_additional_logger_options', container).removeClass('wpo_hidden');
1928 - $('.wpo_logging_options_row', container).text('');
1929 - $('.wpo_logging_status_row', container).text('');
1930 - link.hide();
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();
1931 2580
1932 2581 return false;
1933 2582 });
1934 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 +
1935 2601 $('#wp-optimize-logger-settings').on('change', '.wpo_logger_addition_option', function() {
1936 2602 show_logging_save_settings_reminder();
1937 2603 });
1938 2604
@@ -1938,9 +2604,9 @@
1938 2604
1939 2605 /**
1940 2606 * Handle change of active/inactive status and update hidden field value.
1941 2607 */
1942 - $('.wpo_logger_active_checkbox').on('change', function() {
2608 + $('#settings_form').on('change', '.wpo_logger_active_checkbox', function() {
1943 2609 var checkbox = $(this),
1944 2610 hidden_input = checkbox.closest('label').find('input[type="hidden"]');
1945 2611
1946 2612 hidden_input.val(checkbox.is(':checked') ? '1' : '0');
@@ -1962,9 +2628,11 @@
1962 2628 if (0 == $('#wp-optimize-logging-options .wpo_logging_row').length) {
1963 2629 $('#wp-optimize-logging-options').hide();
1964 2630 }
1965 2631
1966 - show_logging_save_settings_reminder();
2632 + setTimeout(function(){
2633 + $('#wp-optimize-save-main-settings').trigger('click');
2634 + }, 500);
1967 2635
1968 2636 return false;
1969 2637 });
1970 2638
@@ -2025,9 +2693,9 @@
2025 2693 */
2026 2694 function get_add_logging_form_html() {
2027 2695 var i,
2028 2696 select_options = [
2029 - '<option value="">Select destination</option>'
2697 + '<option value="">' + wpoptimize.select_destination + '</option>'
2030 2698 ];
2031 2699
2032 2700 for (i in wpoptimize.loggers_classes_info) {
2033 2701 if (!wpoptimize.loggers_classes_info.hasOwnProperty(i)) continue;
@@ -2038,12 +2706,13 @@
2038 2706 }
2039 2707
2040 2708 return [
2041 2709 '<div class="wpo_add_logger_form">',
2042 - '<select class="wpo_logger_type" name="wpo-logger-type[]">',
2710 + '<select class="wpo_logger_type wpo-select2" name="wpo-logger-type[]">',
2043 2711 select_options.join(''),
2044 - '<select>',
2045 - '<a href="#" class="wpo_delete_logger dashicons dashicons-no-alt"></a>',
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>',
2046 2715 '<div class="wpo_additional_logger_options"></div>',
2047 2716 '</div>'
2048 2717 ].join('');
2049 2718 }
@@ -2067,12 +2736,12 @@
2067 2736 for (i in options) {
2068 2737 if (!options.hasOwnProperty(i)) continue;
2069 2738
2070 2739 if (Array.isArray(options[i])) {
2071 - placeholder = $.trim(options[i][0]);
2072 - validate = $.trim(options[i][1]);
2740 + placeholder = options[i][0].trim();
2741 + validate = options[i][1].trim();
2073 2742 } else {
2074 - placeholder = $.trim(options[i]);
2743 + placeholder = options[i].trim();
2075 2744 validate = '';
2076 2745 }
2077 2746
2078 2747 options_list.push([
@@ -2117,6 +2786,12 @@
2117 2786 $iframe.insertAfter($(this));
2118 2787 $(this).remove();
2119 2788 $iframe.focus();
2120 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);
2121 2796 });
2122 2797 });