PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.7
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.7
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 3.2.7, at js/wpoadmin.js

2,123 lines 64.0 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 send_command = wp_optimize.send_command;
48 var optimization_force = false;
49 var optimization_logged_warnings = false;
50 var force_single_table_optimization = false;
51
52 /*
53 * Enable select all checkbox for optimizations list.
54 */
55 define_select_all_checkbox($('#select_all_optimizations'), $('#optimizations_list .optimization_checkbox'));
56
57 /**
58 * Either display normally, or grey-out, the scheduling options, depending on whether any schedule has been selected.
59 *
60 * @return {string}
61 */
62 function enable_or_disable_schedule_options() {
63 if ($('#enable-schedule').length) {
64 var schedule_enabled = $('#enable-schedule').is(':checked');
65 if (schedule_enabled) {
66 $('#wp-optimize-auto-options').css('opacity', '1');
67 } else {
68 $('#wp-optimize-auto-options').css('opacity', '0.5')
69 }
70 }
71 }
72
73 enable_or_disable_schedule_options();
74
75 $('#enable-schedule').on('change', function () {
76 enable_or_disable_schedule_options();
77 });
78
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 /*
100 * Triggered when the database tabs are loaded.
101 */
102
103 $(document).on('wpo_database_tabs_loaded', function() {
104 /*
105 * Setup table events and tablesorter
106 */
107
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');
112
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}' }
132 }
133 });
134
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();
143 } else {
144 table_footer_line.hide();
145 }
146
147 if (0 == $('#the-list tr:visible', table_list).length) {
148 tables_not_found.show();
149 } else {
150 tables_not_found.hide();
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 });
190
191 /**
192 * Temporarily show a dashboard notice, and then remove it. The HTML will be prepended to the .wrap.wp-optimize-wrap element.
193 *
194 * @param {String} html_contents HTML to display.
195 * @param {String} where CSS selector of where to prepend the HTML to.
196 * @param {Number} [delay=15] The number of seconds to wait before removing the message.
197 *
198 * @return {string}
199 */
200 function temporarily_display_notice(html_contents, where, delay) {
201 where = ('undefined' === typeof where) ? '#wp-optimize-wrap' : where;
202 delay = ('undefined' === typeof delay) ? 15 : delay;
203 $(html_contents).hide().prependTo(where).slideDown('fast').delay(delay * 1000).slideUp('fast', function () {
204 $(this).remove();
205 });
206 }
207
208 /**
209 * Send a request to disable or enable comments or trackbacks
210 *
211 * @param {string} type - either "comments" or "trackbacks"
212 * @param {boolean} enable - whether to enable, or, to disable
213 *
214 * @return {string}
215 */
216 function enable_or_disable_feature(type, enable) {
217 var data = {
218 type: type,
219 enable: enable ? 1 : 0
220 };
221
222 $('#' + type + '_spinner').show();
223
224 send_command('enable_or_disable_feature', data, function (resp) {
225 $('#' + type + '_spinner').hide();
226
227 if (resp && resp.hasOwnProperty('output')) {
228 for (var i = 0, len = resp.output.length; i < len; i++) {
229 var new_html = '<div class="updated"><p>' + resp.output[i] + '</p></div>';
230 temporarily_display_notice(new_html, '#' + type + '_notice');
231 }
232 }
233 if (resp && resp.hasOwnProperty('messages')) {
234 $('#' + type + '_actionmsg').html(resp.messages.join(' - '));
235 }
236 });
237 }
238
239 $('#wp-optimize-disable-enable-trackbacks-enable').on('click', function () {
240 enable_or_disable_feature('trackbacks', true);
241 });
242
243 $('#wp-optimize-disable-enable-trackbacks-disable').on('click', function () {
244 enable_or_disable_feature('trackbacks', false);
245 });
246
247 $('#wp-optimize-disable-enable-comments-enable').on('click', function () {
248 enable_or_disable_feature('comments', true);
249 });
250
251 $('#wp-optimize-disable-enable-comments-disable').on('click', function () {
252 enable_or_disable_feature('comments', false);
253 });
254
255 // Main menu
256 $('.wpo-pages-menu').on('click', 'a', function(e) {
257 e.preventDefault();
258 if (!$(this).is('.active')) {
259 $('.wpo-pages-menu a.active').removeClass('active');
260 $('.wpo-page.active').removeClass('active');
261 $(this).addClass('active');
262 $('.wpo-page[data-whichpage="' + $(this).data('menuslug') + '"]').addClass('active');
263 window.scroll(0, 0);
264
265 // Trigger a global event when changing page
266 $('#wp-optimize-wrap').trigger('page-change', { page: $(this).data('menuslug') });
267 }
268
269 // Close the menu on mobile
270 $('#wp-optimize-nav-page-menu').trigger('click');
271
272 });
273
274 $('#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 // 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
285 // set a time out, as needs to be done once the rest is loaded
286 setTimeout(function() {
287 // Trigger page-change event on load
288 $('#wp-optimize-wrap').trigger('page-change', { page: $('.wpo-pages-menu a.active').data('menuslug') });
289 }, 500);
290
291 // Tabs menu
292 $('.nav-tab-wrapper .nav-tab').on('click', function (e) {
293 e.preventDefault();
294
295 var clicked_tab_id = $(this).attr('id'),
296 container = $(this).closest('.nav-tab-wrapper');
297
298 if (!clicked_tab_id) { return; }
299
300 toggle_mobile_menu(false);
301 // Mobile menu TABS toggle
302 if ($(this).is('[role="toggle-menu"]')) {
303 toggle_mobile_menu(true);
304 return;
305 }
306
307 container.find('.nav-tab:not(#wp-optimize-nav-tab-' + clicked_tab_id + ')').removeClass('nav-tab-active');
308
309 $(this).addClass('nav-tab-active');
310 $(this).closest('.wpo-page').find('.wp-optimize-nav-tab-contents').hide();
311 $('#' + clicked_tab_id + '-contents').show();
312
313 // Trigger global events on tab change
314 $('#wp-optimize-wrap').trigger('tab-change', { page: $(this).data('page'), tab: $(this).data('tab') });
315 $('#wp-optimize-wrap').trigger('tab-change/'+$(this).data('page')+'/'+$(this).data('tab'), { content: $('#' + clicked_tab_id + '-contents')});
316
317 });
318
319 // Mobile menu toggle
320 $('#wp-optimize-nav-page-menu').on('click', function(e) {
321 e.preventDefault();
322 $(this).toggleClass('opened');
323 });
324
325 /*
326 * Setup a simple cross-pages/tabs navigation.
327 *
328 * Basic example: <button class="js--wpo-goto" data-page="wpo_minify" data-tab="status">Go to the minify page, status tab</button>
329 */
330 $('#wp-optimize-wrap').on('click', '.js--wpo-goto', function(e) {
331 e.preventDefault();
332 // get the page and tab
333 var page = $(this).data('page');
334 var tab = $(this).data('tab');
335 if (page) {
336 // Trigger a page change
337 $('.wpo-pages-menu a[data-menuslug="' + page + '"]').trigger('click');
338 }
339 if (tab) {
340 // Change tab change
341 $('.wpo-page.active .nav-tab-wrapper a[data-tab="' + tab + '"]').trigger('click');
342 }
343 });
344
345 /**
346 * Toggle Mobile menu
347 *
348 * @param {bool} open
349 *
350 * @return {void}
351 */
352 function toggle_mobile_menu(open) {
353 if (open) {
354 $('#wp-optimize-wrap').addClass('wpo-mobile-menu-opened');
355 } else {
356 $('#wp-optimize-wrap').removeClass('wpo-mobile-menu-opened');
357 }
358 }
359
360 var database_tabs_loaded = false;
361 // When showing the tables tab
362 $('#wp-optimize-wrap').on('tab-change/WP-Optimize/tables', function(e) {
363 get_database_tabs();
364 });
365
366 // When showing the tables tab
367 $('#wp-optimize-wrap').on('tab-change/WP-Optimize/optimize', function(event, data) {
368 get_database_tabs();
369 });
370
371 // When showing the settings tab
372 $('#wp-optimize-wrap').on('tab-change/wpo_settings/settings', function(event, data) {
373 // If the innodb_force_optimize--container is present, fetch the required data.
374 // We load the database tabs together, as they need the same processing.
375 if (data.content.find('.innodb_force_optimize--container').length) get_database_tabs();
376 });
377
378 /**
379 * Get the data for the database tabs. We get them at the same time, as they both need the same time consuming requests.
380 */
381 function get_database_tabs() {
382 if (database_tabs_loaded) return;
383 var container = $('.wpo-page[data-whichpage=WP-Optimize]');
384 var shade = container.find('.wpo_shade');
385 shade.removeClass('hidden');
386 send_command('get_database_tabs', {}, function(response) {
387 // Set the satus to true, to prevent loading again.
388 database_tabs_loaded = true;
389
390 // Updtate the optimizations tab
391 if (response.hasOwnProperty('optimizations')) {
392 container.find('.wp-optimize-optimizations-table-placeholder').replaceWith(response.optimizations);
393 }
394
395 // Updtate the optimizations tables list
396 update_tables_list(response);
397
398 $(document).trigger('wpo_database_tabs_loaded');
399
400 }).always(function() {
401 shade.addClass('hidden');
402 });
403 }
404
405 /**
406 * Gathers the settings from the settings tab and return in selected format.
407 *
408 * @param {string} output_format optional param 'object' or 'string'.
409 *
410 * @return (string) - serialized settings.
411 */
412 function gather_settings(output_format) {
413 var form_data = '',
414 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-']");
416
417 if ('object' == output_format) {
418 form_data = $form_elements.serializeJSON({useIntKeysAsArrayIndex: true});
419 } else {
420 // Excluding the unnecessary 'action' input avoids triggering a very mis-conceived mod_security rule seen on one user's site.
421 form_data = $form_elements.serialize();
422
423 // 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-"]')
425 .filter(function (idx) {
426 return $(this).prop('checked') == false
427 }),
428 function (idx, el) {
429 // Attach matched element names to the form_data with chosen value.
430 var empty_val = '0';
431 form_data += '&' + $(el).attr('name') + '=' + empty_val;
432 }
433 );
434 }
435
436 return form_data;
437 }
438
439 /**
440 * Runs after all queued commands done and sends optimizations_done command
441 *
442 * @return {string}
443 */
444 function process_done() {
445 send_command('optimizations_done', {}, function () {});
446 // Reset the warning flag
447 optimization_logged_warnings = false;
448 }
449
450 /**
451 * Proceses the queue
452 *
453 * @return void
454 */
455 function process_queue() {
456 if (!queue.get_lock()) {
457 if (debug_level > 0) {
458 console.log("WP-Optimize: process_queue(): queue is currently locked - exiting");
459 }
460 return;
461 }
462
463 if (debug_level > 0) {
464 console.log("WP-Optimize: process_queue(): got queue lock");
465 }
466
467 var id = queue.peek();
468 var blog_id = 0;
469 var sites_container = $("#wpo_all_sites");
470 var active_site = sites_container.data('active_site');
471
472 // Check to see if an object has been returned.
473 if (typeof id == 'object') {
474 data = id;
475 id = id.optimization_id;
476 blog_id = data.blog_id;
477
478 if ("undefined" == typeof active_site) {
479 sites_container.data('active_site', blog_id);
480 do_site_ui_update(blog_id, 0);
481 } else if (active_site != blog_id) {
482 var prev_blog_id = active_site;
483 sites_container.data('active_site', blog_id);
484 do_site_ui_update(blog_id, prev_blog_id);
485 }
486
487 } else {
488 data = {};
489 }
490
491 if ('undefined' === typeof id) {
492 if (debug_level > 0) console.log("WP-Optimize: process_queue(): queue is apparently empty - exiting");
493 queue.unlock();
494 var prev_blog_id = sites_container.data('active_site');
495 do_site_ui_update(0, prev_blog_id);
496 process_done();
497 return;
498 }
499
500 if (debug_level > 0) console.log("WP-Optimize: process_queue(): processing item: " + id);
501
502 queue.dequeue();
503
504 $(document).trigger(['do_optimization_', id, '_start'].join(''));
505
506 if ('optimizetables' === id) {
507 // Display the table name being optimized
508 $('#optimization_info_' + id).html(wpoptimize.optimizing_table + ' ' + data.optimization_table);
509
510 // Set extra options for the request
511 var timeout = parseInt(wpoptimize.table_optimization_timeout) ? parseInt(wpoptimize.table_optimization_timeout) : 120000;
512 var request_options = {
513 timeout: timeout,
514 error: function(error, type) {
515 optimization_logged_warnings = true;
516 if ('timeout' === type) {
517 console.warn('The request to optimize the table ' + data.optimization_table + ' timed out after ' + (timeout / 1000) + ' seconds');
518 } else {
519 console.warn('There was an error when running the optimization "' + id + '".', type, error, data);
520 }
521 if (queue.is_empty()) {
522 var blog_id = sites_container.data('active_site');
523 do_site_ui_update(blog_id, 0);
524 $('#optimization_spinner_' + id).hide();
525 $('#optimization_checkbox_' + id).show();
526 $('.optimization_button_' + id).prop('disabled', false);
527 $('#optimization_info_' + id).html(wpoptimize.optimization_complete + ' ' + wpoptimize.with_warnings);
528 }
529
530 setTimeout(function () {
531 queue.unlock(); process_queue();
532 }, 500);
533 }
534 }
535 } else {
536 var request_options = {};
537 }
538
539 send_command('do_optimization', { optimization_id: id, data: data }, function (response) {
540 $('#optimization_spinner_' + id).hide();
541 $('#optimization_checkbox_' + id).show();
542 $('.optimization_button_' + id).prop('disabled', false);
543
544 $(document).trigger(['do_optimization_', id, '_done'].join(''), response);
545
546 if (response) {
547 var total_output = '';
548 for (var i = 0, len = response.errors.length; i < len; i++) {
549 total_output += '<span class="error">' + response.errors[i] + '</span><br>';
550 }
551 for (var i = 0, len = response.messages.length; i < len; i++) {
552 total_output += response.errors[i] + '<br>';
553 }
554 for (var i = 0, len = response.result.output.length; i < len; i++) {
555 total_output += response.result.output[i] + '<br>';
556 }
557 $('#optimization_info_' + id).html(total_output);
558 if (response.hasOwnProperty('status_box_contents')) {
559 $('#wp_optimize_status_box').css('opacity', '1').find('.inside').html(response.status_box_contents);
560 }
561 if (response.hasOwnProperty('table_list')) {
562 $('#wpoptimize_table_list tbody').html($(response.table_list).find('tbody').html());
563 }
564 if (response.hasOwnProperty('total_size')) {
565 $('#optimize_current_db_size').html(response.total_size);
566 }
567
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) : ''));
576 } else {
577 $('#optimization_checkbox_' + id).hide();
578 $('#optimization_spinner_' + id).show();
579 $('.optimization_button_' + id).prop('disabled', true);
580 }
581 }
582
583 // check if we need update unapproved comments count.
584 if (response.result.meta && response.result.meta.hasOwnProperty('awaiting_mod')) {
585 var awaiting_mod = response.result.meta.awaiting_mod;
586 if (awaiting_mod > 0) {
587 $('#adminmenu .awaiting-mod .pending-count').remove(awaiting_mod);
588 } else {
589 // if there is no unapproved comments then remove bullet.
590 $('#adminmenu .awaiting-mod').remove();
591 }
592 }
593 }
594 setTimeout(function () {
595 queue.unlock(); process_queue();
596 }, 500);
597 }, true, request_options);
598 }
599
600 /**
601 * Update UI of sites list based on which site is currently being optimizated
602 *
603 * @param {Number} blog_id - current site id being optimized
604 * @param {Number} prev_blog_id - previous site id
605 *
606 * @return void
607 */
608 function do_site_ui_update(blog_id, prev_blog_id) {
609 if (0 != prev_blog_id) {
610 $("#site-" + prev_blog_id).show();
611 $("#optimization_spinner_site-" + prev_blog_id).hide();
612 }
613 $("#site-" + blog_id).hide();
614 $("#optimization_spinner_site-" + blog_id).show();
615 }
616
617 /**
618 * Runs a specified optimization, displaying the progress and results in the optimization's row
619 *
620 * @param {string} id - The optimization ID
621 *
622 * @return void
623 */
624 function do_optimization(id) {
625 var $optimization_row = $('#wp-optimize-nav-tab-contents-optimize .wp-optimize-settings-' + id);
626
627 if (!$optimization_row) {
628 console.log("do_optimization: row corresponding to this optimization (" + id + ") not found");
629 }
630
631 // check if there any additional inputs checkboxes.
632 var additional_data = {},
633 additional_data_length = 0;
634
635 $('input[type="checkbox"]', $('#optimization_info_' + id)).each(function() {
636 var checkbox = $(this);
637
638 if (checkbox.is(':checked')) {
639 additional_data[checkbox.attr('name')] = checkbox.val();
640 additional_data_length++;
641 }
642 });
643
644 // don't run optimization if optimization active.
645 if (true == $('.optimization_button_' + id).prop('disabled')) return;
646
647 var no_queue_actions_added = false;
648
649 // Check if it is DB optimize.
650 if ('optimizetables' == id) {
651 var optimization_tables = $('#wpoptimize_table_list #the-list tr'),
652 filter_by_blog_id = $('#wpo_sitelist_moreoptions').length > 0 && $('#wpo_sitelist_moreoptions').is(':visible'),
653 selected_sites = [];
654
655 // Get list of selected sites.
656 if (filter_by_blog_id) {
657 selected_sites = $('#wpo_sitelist_moreoptions input[type="checkbox"]:checked').map(function() {
658 return parseInt($(this).val());
659 }).get();
660 }
661
662 no_queue_actions_added = true;
663
664 // Check if there are any tables to be optimized.
665 $(optimization_tables).each(function (index) {
666 // Get information from each td.
667 var $table_information = $(this).find('td');
668
669 // Get table type information.
670 var table_type = $(this).data('type');
671 var table = $(this).data('tablename');
672 var optimizable = $(this).data('optimizable');
673 var blog_id = $(this).data('blog_id') ? parseInt($(this).data('blog_id')) : 1;
674 var in_selected_sites = true;
675
676
677 // Check if table is in the list of selected sites (multisite mode).
678 if (filter_by_blog_id && -1 == selected_sites.indexOf(blog_id)) {
679 in_selected_sites = false;
680 }
681
682 // Make sure the table isnt blank.
683 if ('' != table && in_selected_sites) {
684 // Check if table is optimizable or optimization forced by user.
685 if (1 == parseInt(optimizable) || optimization_force) {
686 var data = {
687 optimization_id: id,
688 blog_id: blog_id,
689 optimization_table: table,
690 optimization_table_type: table_type,
691 optimization_force: optimization_force
692 };
693
694 queue.enqueue(data);
695
696 no_queue_actions_added = false;
697 }
698 }
699 });
700 } else if (additional_data_length > 0) {
701 // check if additional data passed for optimization.
702 data = {
703 optimization_id: id
704 };
705
706 for (var i in additional_data) {
707 if (!additional_data.hasOwnProperty(i)) continue;
708 data[i] = additional_data[i];
709 }
710
711 queue.enqueue(data);
712 } else {
713 queue.enqueue(id);
714 }
715
716 // if new actions was not added in tasks queue then we don't process queue.
717 if (no_queue_actions_added) return;
718
719 $('#optimization_checkbox_' + id).hide();
720 $('#optimization_spinner_' + id).show();
721 $('.optimization_button_' + id).prop('disabled', true);
722
723 $('#optimization_info_' + id).html('...');
724
725 process_queue();
726 }
727
728
729 /**
730 * Run action and save selected sites list options.
731 *
732 * @param {function} action - action to do after save.
733 *
734 * @return void
735 */
736 function save_sites_list_and_do_action(action) {
737 // if multisite mode then save sites list before action.
738 if ($('#wpo_settings_sites_list').length) {
739 // save wpo-sites settings.
740 send_command('save_site_settings', {'wpo-sites': get_selected_sites_list()}, function () {
741 // do action.
742 if (action) action();
743 });
744 } else {
745 // do action.
746 if (action) action();
747 }
748 }
749
750 /**
751 * Returns list of selected sites list.
752 *
753 * @return {Array}
754 */
755 function get_selected_sites_list() {
756 var wpo_sites = [];
757
758 $('#wpo_settings_sites_list input[type="checkbox"]').each(function () {
759 var checkbox = $(this);
760 if (checkbox.is(':checked')) {
761 wpo_sites.push(checkbox.attr('value'));
762 }
763 });
764
765 return wpo_sites;
766 }
767
768 /*
769 * Run single optimization click.
770 */
771 $('#wp-optimize-nav-tab-WP-Optimize-optimize-contents').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
772 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
773 if (!optimization_id) {
774 console.log("Optimization ID corresponding to pressed button not found");
775 return;
776 }
777 // if run button disabled then don't run this optimization.
778 if (true == $('.optimization_button_' + optimization_id).prop('disabled')) return;
779 // disable run button before save sites list.
780 $('.optimization_button_' + optimization_id).prop('disabled', true);
781
782 save_sites_list_and_do_action(function() {
783 $('.optimization_button_' + optimization_id).prop('disabled', false);
784 do_optimization(optimization_id);
785 });
786 });
787
788 /*
789 * Run all optimizations click.
790 */
791 $('#wp-optimize-nav-tab-WP-Optimize-optimize-contents').on('click', '#wp-optimize', function (e) {
792 var run_btn = $(this);
793
794 e.preventDefault();
795
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();
801 });
802 });
803
804 /**
805 * Sent command to run selected optimizations and auto backup if selected
806 *
807 * @return void
808 */
809 function run_optimizations() {
810 var auto_backup = false;
811
812 if ($('#enable-auto-backup').is(":checked")) {
813 auto_backup = true;
814 }
815
816 // Save the click option.
817 save_auto_backup_options();
818
819 // Only run the backup if tick box is checked.
820 if (auto_backup == true) {
821 take_a_backup_with_updraftplus(run_optimization);
822 } else {
823 // Run optimizations.
824 run_optimization();
825 }
826 }
827
828 /**
829 * Take a backup with UpdraftPlus if possible.
830 *
831 * @param {Function} callback
832 * @param {String} file_entities
833 *
834 * @return void
835 */
836 function take_a_backup_with_updraftplus(callback, file_entities) {
837 // Set default for file_entities to empty string
838 if ('undefined' == typeof file_entities) file_entities = '';
839 var exclude_files = file_entities ? 0 : 1;
840
841 if (typeof updraft_backupnow_inpage_go === 'function') {
842 updraft_backupnow_inpage_go(function () {
843 // Close the backup dialogue.
844 $('#updraft-backupnow-inpage-modal').dialog('close');
845
846 if (callback) callback();
847
848 }, file_entities, 'autobackup', 0, exclude_files, 0, wpoptimize.automatic_backup_before_optimizations);
849 } else {
850 if (callback) callback();
851 }
852 }
853
854 /**
855 * Save all auto backup options.
856 *
857 * @return void
858 */
859 function save_auto_backup_options() {
860 var options = gather_settings('object');
861 options['auto_backup'] = $('#enable-auto-backup').is(":checked");
862
863 send_command('save_auto_backup_option', options);
864 }
865
866 // Show/hide sites list for multi-site settings.
867 var wpo_settings_sites_list = $('#wpo_settings_sites_list'),
868 wpo_settings_sites_list_ul = wpo_settings_sites_list.find('ul').first(),
869 wpo_settings_sites_list_items = $('input[type="checkbox"]', wpo_settings_sites_list_ul),
870 wpo_settings_all_sites_checkbox = wpo_settings_sites_list.find('#wpo_all_sites'),
871 wpo_sitelist_show_moreoptions_link = $('#wpo_sitelist_show_moreoptions'),
872 wpo_sitelist_moreoptions_div = $('#wpo_sitelist_moreoptions'),
873
874 wpo_settings_sites_list_cron = $('#wpo_settings_sites_list_cron'),
875 wpo_settings_sites_list_cron_ul = wpo_settings_sites_list_cron.find('ul').first(),
876 wpo_settings_sites_list_cron_items = $('input[type="checkbox"]', wpo_settings_sites_list_cron_ul),
877 wpo_settings_all_sites_cron_checkbox = wpo_settings_sites_list_cron.find('#wpo_all_sites_cron'),
878 wpo_sitelist_show_moreoptions_cron_link = $('#wpo_sitelist_show_moreoptions_cron'),
879 wpo_sitelist_moreoptions_cron_div = $('#wpo_sitelist_moreoptions_cron');
880
881 // sites list for manual run.
882 define_moreoptions_settings(
883 wpo_sitelist_show_moreoptions_link,
884 wpo_sitelist_moreoptions_div,
885 wpo_settings_all_sites_checkbox,
886 wpo_settings_sites_list_items
887 );
888
889 var sites_list_clicked_count = 0;
890
891 $([wpo_settings_all_sites_checkbox, wpo_settings_sites_list_items]).each(function() {
892 $(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();
897 }, 1000);
898 });
899 });
900
901 // sites list for cron run.
902 define_moreoptions_settings(
903 wpo_sitelist_show_moreoptions_cron_link,
904 wpo_sitelist_moreoptions_cron_div,
905 wpo_settings_all_sites_cron_checkbox,
906 wpo_settings_sites_list_cron_items
907 );
908
909 /**
910 * Attach event handlers for more options list showed by clicking on show_moreoptions_link.
911 *
912 * @param show_moreoptions_link
913 * @param more_options_div
914 * @param all_items_checkbox
915 * @param items_list
916 *
917 * @return boolean
918 */
919 function define_moreoptions_settings(show_moreoptions_link, more_options_div, all_items_checkbox, items_list) {
920 // toggle show options on click.
921 show_moreoptions_link.on('click', function () {
922 if (!more_options_div.hasClass('wpo_always_visible')) more_options_div.toggleClass('wpo_hidden');
923 return false;
924 });
925
926 // if "all items" checked/unchecked then check/uncheck items in the list.
927 define_select_all_checkbox(all_items_checkbox, items_list);
928 }
929
930 /**
931 * Defines "select all" check box, where all_items_checkbox is a select all check box jQuery object
932 * and items_list is a list of checkboxes assigned with all_items_checkbox.
933 *
934 * @param {Object} all_items_checkbox
935 * @param {Object} items_list
936 *
937 * @return void
938 */
939 function define_select_all_checkbox(all_items_checkbox, items_list) {
940 // if "all items" checked/unchecked then check/uncheck items in the list.
941 all_items_checkbox.on('change', function () {
942 if (all_items_checkbox.is(':checked')) {
943 items_list.prop('checked', true);
944 } else {
945 items_list.prop('checked', false);
946 }
947
948 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
949 });
950
951 items_list.on('change', function () {
952 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
953 });
954
955 update_wpo_all_items_checkbox_state(all_items_checkbox, items_list);
956
957 }
958
959 /**
960 * Update state of "all items" checkbox depends on state all items in the list.
961 *
962 * @param all_items_checkbox
963 * @param all_items
964 *
965 * @return void
966 */
967 function update_wpo_all_items_checkbox_state(all_items_checkbox, all_items) {
968 var all_items_count = 0, checked_items_count = 0;
969
970 all_items.each(function () {
971 if ($(this).is(':checked')) {
972 checked_items_count++;
973 }
974 all_items_count++;
975 });
976
977 // update label text if need.
978 if (all_items_checkbox.next().is('label') && all_items_checkbox.next().data('label')) {
979 var label = all_items_checkbox.next(),
980 label_mask = label.data('label');
981
982 if (all_items_count == checked_items_count) {
983 label.text(label_mask);
984 } else {
985 label.text(label_mask.replace('all', [checked_items_count, ' of ', all_items_count].join('')));
986 }
987 }
988
989 if (all_items_count == checked_items_count) {
990 all_items_checkbox.prop('checked', true);
991 } else {
992 all_items_checkbox.prop('checked', false);
993 }
994 }
995
996 /**
997 * Running the optimizations for the selected options
998 *
999 * @return {[type]} optimizations
1000 */
1001 function run_optimization() {
1002 $optimizations = $('#optimizations_list .optimization_checkbox:checked');
1003
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 }
1015 });
1016
1017 var optimization_options = {};
1018
1019 $optimizations.each(function (index) {
1020 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
1021 if (!optimization_id) {
1022 console.log("Optimization ID corresponding to pressed button not found");
1023 return;
1024 }
1025 // An empty object - in future, options may be implemented.
1026 optimization_options[optimization_id] = { active: 1 };
1027 do_optimization(optimization_id);
1028 });
1029
1030 send_command('save_manual_run_optimization_options', optimization_options);
1031 }
1032
1033 /**
1034 * Uptate the tables list
1035 *
1036 * @param {object} response
1037 */
1038 function update_tables_list(response) {
1039 if (response.hasOwnProperty('table_list')) {
1040 var resort = true,
1041 // add a callback, as desired
1042 callback = function(table) {
1043 $('#wpoptimize_table_list tbody').css('opacity', '1');
1044 };
1045
1046 // update body with new content.
1047 $("#wpoptimize_table_list tbody").remove();
1048 $("#wpoptimize_table_list thead").after(response.table_list);
1049
1050 $("#wpoptimize_table_list").trigger("updateAll", [resort, callback]);
1051 }
1052
1053 if (response.hasOwnProperty('total_size')) {
1054 $('#optimize_current_db_size').html(response.total_size);
1055 }
1056
1057 if (response.hasOwnProperty('show_innodb_force_optimize')) {
1058 $('.innodb_force_optimize--container').toggleClass('hidden', !response.show_innodb_force_optimize);
1059 }
1060
1061 change_actions_column_visibility();
1062 update_single_table_optimization_buttons(force_single_table_optimization);
1063 }
1064
1065 $('#wp_optimize_table_list_refresh').on('click', function (e) {
1066 e.preventDefault();
1067 var shade = $(this).closest('.wpo-tab-postbox').find('.wpo_shade');
1068 shade.removeClass('hidden');
1069 $('#wpoptimize_table_list tbody').css('opacity', '0.5');
1070 send_command('get_table_list', {refresh_plugin_json: true}, update_tables_list).always(function() {
1071 shade.addClass('hidden');
1072 });
1073 });
1074
1075 $('#database_settings_form, #settings_form').on('click', '.wpo-save-settings', function (e) {
1076 e.preventDefault();
1077 var form = $(this).closest('form');
1078 var spinner = form.find('.wpo-saving-settings');
1079 var form_data = gather_settings();
1080
1081 form.trigger('wpo-saving-form-data');
1082
1083 if (form.form_errors.has_errors()) return;
1084
1085 spinner.show();
1086
1087 // when optimizations list in the document - send information about selected optimizations.
1088 if ($('#optimizations_list').length) {
1089 $('#optimizations_list .optimization_checkbox:checked').each(function() {
1090 var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
1091 if (optimization_id) {
1092 form_data += '&optimization-options['+optimization_id+'][active]=1';
1093 }
1094 });
1095 }
1096
1097 if ($('#purge_cache_permissions').length) {
1098 if (!$('#purge_cache_permissions').val()) {
1099 form_data += '&purge_cache_permissions[]';
1100 }
1101 }
1102
1103 send_command('save_settings', form_data, function (resp) {
1104 spinner.closest('div').find('.save-done').show().delay(5000).fadeOut();
1105
1106 if (resp && resp.hasOwnProperty('save_results') && resp.save_results && resp.save_results.hasOwnProperty('errors')) {
1107 for (var i = 0, len = resp.save_results.errors.length; i < len; i++) {
1108 var new_html = '<div class="error">' + resp.errors[i] + '</div>';
1109 temporarily_display_notice(new_html, '#wp-optimize-settings-save-results');
1110 }
1111 }
1112 if (resp && resp.hasOwnProperty('status_box_contents')) {
1113 $(resp.status_box_contents).each(function(index, el) {
1114 if ($(el).is('#wp_optimize_status_box')) {
1115 $('#wp_optimize_status_box').replaceWith($(el));
1116 }
1117 });
1118 }
1119
1120 if (resp && resp.hasOwnProperty('optimizations_table')) {
1121 $('#optimizations_list').replaceWith(resp.optimizations_table);
1122 }
1123
1124 // Need to refresh the page if enable-admin-menu tick state has changed.
1125 if (resp.save_results.refresh) {
1126 location.reload();
1127 }
1128 }).always(function() {
1129 spinner.hide();
1130 });
1131 });
1132
1133 /*
1134 * Handle Wipe Settings click.
1135 */
1136 $('#settings_form').on('click', '.wpo-wipe-settings', function() {
1137 var spinner = $(this).parent().find('.wpo_spinner');
1138
1139 spinner.show();
1140
1141 send_command('wipe_settings', {}, function() {
1142 spinner.next().removeClass('display-none').delay(5000).fadeOut();
1143 alert(wpoptimize.settings_have_been_deleted_successfully);
1144 location.replace(wpoptimize.settings_page_url);
1145 }).always(function() {
1146 spinner.hide();
1147 });
1148
1149 });
1150
1151 $('#wp-optimize-wrap').on('click', '#wp_optimize_status_box_refresh', function (e) {
1152 e.preventDefault();
1153 $('#wp_optimize_status_box').css('opacity', '0.5');
1154 send_command('get_status_box_contents', null, function (resp) {
1155 $('#wp_optimize_status_box').css('opacity', '1');
1156 $(resp).each(function(index, el) {
1157 if ($(el).is('#wp_optimize_status_box')) {
1158 $('#wp_optimize_status_box').replaceWith($(el));
1159 }
1160 });
1161
1162 });
1163 });
1164
1165 /**
1166 * Run single table optimization. Handle click on Optimize button.
1167 *
1168 * @param {Object} btn jQuery object clicked Optimize button
1169 *
1170 * @return {void}
1171 */
1172 function run_single_table_optimization(btn) {
1173 var spinner = btn.next(),
1174 action_done_icon = spinner.next(),
1175 table_name = btn.data('table'),
1176 table_type = btn.data('type'),
1177 data = {
1178 optimization_id: 'optimizetables',
1179 optimization_table: table_name,
1180 optimization_table_type: table_type
1181 };
1182 btn.hide();
1183 // if checked force button then send force value.
1184 if (force_single_table_optimization) {
1185 data['optimization_force'] = true;
1186 }
1187
1188 spinner.removeClass('visibility-hidden');
1189
1190 send_command('do_optimization', { optimization_id: 'optimizetables', data: data }, function (response) {
1191 if (response.result.meta.error) {
1192 btn.closest('tr').html('<td colspan="8" class="no-table"><p>' + response.result.meta.message + '</p></td>');
1193 setTimeout(function() {
1194 $('#wp_optimize_table_list_refresh').trigger('click');
1195 }, 2000);
1196 } else {
1197 if (response.result.meta.tableinfo) {
1198 var row = btn.closest('tr'),
1199 meta = response.result.meta,
1200 tableinfo = meta.tableinfo;
1201
1202 update_single_table_information(row, tableinfo);
1203
1204 // update total overhead.
1205 $('#wpoptimize_table_list > tbody:last th:eq(6)').html(['<span style="color:', meta.overhead > 0 ? '#0000FF' : '#004600', '">', meta.overhead_formatted,'</span>'].join(''));
1206 }
1207 }
1208
1209 btn.prop('disabled', false);
1210 spinner.addClass('visibility-hidden');
1211 action_done_icon.show().removeClass('visibility-hidden').delay(2500).fadeOut('fast', function() {
1212 btn.show();
1213 });
1214 });
1215 }
1216
1217 /**
1218 * Update information about single table in the database tables list.
1219 *
1220 * @param {Object} row jQuery object for TR html tag.
1221 * @param {Object} tableinfo
1222 *
1223 * @return {void}
1224 */
1225 function update_single_table_information(row, tableinfo) {
1226 // update table information in row.
1227 $('td:eq(2)', row).text(tableinfo.rows);
1228 $('td:eq(3)', row).text(tableinfo.data_size);
1229 $('td:eq(4)', row).text(tableinfo.index_size);
1230 $('td:eq(5)', row).text(tableinfo.type);
1231
1232 if (tableinfo.is_optimizable) {
1233 $('td:eq(6)', row).html(['<span style="color:', tableinfo.overhead > 0 ? '#0000FF' : '#004600', '">', tableinfo.overhead,'</span>'].join(''));
1234 } else {
1235 $('td:eq(6)', row).html('<span color="#0000FF">-</span>');
1236 }
1237
1238 }
1239
1240 /**
1241 * Update single table optimization buttons state depends on force_optimization value.
1242 *
1243 * @param {boolean} force_optimization See if we need to force optimization
1244 *
1245 * @return {void}
1246 */
1247 function update_single_table_optimization_buttons(force_optimization) {
1248 $('.run-single-table-optimization').each(function() {
1249 var btn = $(this);
1250
1251 if (btn.data('disabled')) {
1252 if (force_optimization) {
1253 btn.prop('disabled', false);
1254 } else {
1255 btn.prop('disabled', true);
1256 }
1257 }
1258 });
1259 }
1260
1261 /**
1262 * Returns true if single site mode or multisite and at least one site selected;
1263 *
1264 * @return {boolean}
1265 */
1266 function is_sites_selected() {
1267 return (0 == wpo_settings_sites_list.length || 0 != $('input[type="checkbox"]:checked', wpo_settings_sites_list).length);
1268 }
1269
1270 /**
1271 * Update optimizations info texts.
1272 *
1273 * @param {Object} response object returned by command get_optimizations_info.
1274 *
1275 * @return {void}
1276 */
1277 function update_optimizations_info_view(response) {
1278 var i, dom_id, info;
1279
1280 // @codingStandardsIgnoreLine
1281 if (!response) return;
1282
1283 for (i in response) {
1284 if (!response.hasOwnProperty(i)) continue;
1285
1286 dom_id = ['#wp-optimize-settings-', response[i].dom_id].join('');
1287 info = response[i].info ? response[i].info.join('<br>') : '';
1288
1289 $(dom_id + ' .wp-optimize-settings-optimization-info').html(info);
1290 }
1291 }
1292
1293 var get_optimizations_info_cache = {};
1294
1295 /**
1296 * Send command for get optimizations info and update view.
1297 *
1298 * @return {void}
1299 */
1300 function update_optimizations_info() {
1301 var cache_key = ['', get_selected_sites_list().join('_')].join('');
1302
1303 // if information saved in cache show it.
1304 if (get_optimizations_info_cache.hasOwnProperty(cache_key)) {
1305 update_optimizations_info_view(get_optimizations_info_cache[cache_key]);
1306 } else {
1307 // else send command update cache and update view.
1308 send_command('get_optimizations_info', {'wpo-sites':get_selected_sites_list()}, function(response) {
1309 // @codingStandardsIgnoreLine
1310 if (!response) return;
1311 get_optimizations_info_cache[cache_key] = response;
1312 update_optimizations_info_view(response);
1313 });
1314 }
1315 }
1316
1317 /*
1318 * Check if settings file selected for import.
1319 */
1320 $('#wpo_import_settings_btn').on('click', function(e) {
1321 var file_input = $('#wpo_import_settings_file'),
1322 filename = file_input.val(),
1323 wpo_import_file_file = file_input[0].files[0],
1324 wpo_import_file_reader = new FileReader();
1325
1326 $('#wpo_import_settings_btn').prop('disabled', true);
1327
1328 if (!/\.json$/.test(filename)) {
1329 e.preventDefault();
1330 $('#wpo_import_settings_btn').prop('disabled', false);
1331 $('#wpo_import_error_message').text(wpoptimize.please_select_settings_file).slideDown();
1332 return false;
1333 }
1334
1335 wpo_import_file_reader.onload = function() {
1336 import_settings(this.result);
1337 };
1338
1339 wpo_import_file_reader.readAsText(wpo_import_file_file);
1340
1341 return false;
1342 });
1343
1344 /**
1345 * Send import settings command.
1346 *
1347 * @param {string} settings encoded settings in json string.
1348 *
1349 * @return {void}
1350 */
1351 function import_settings(settings) {
1352 var loader = $('#wpo_import_spinner'),
1353 success_message = $('#wpo_import_success_message'),
1354 error_message = $('#wpo_import_error_message');
1355
1356 loader.show();
1357 send_command('import_settings', {'settings': settings}, function(response) {
1358 loader.hide();
1359 if (response && response.errors && response.errors.length) {
1360 error_message.text(response.errors.join('<br>'));
1361 error_message.slideDown();
1362 } else if (response && response.messages && response.messages.length) {
1363 success_message.text(response.messages.join('<br>'));
1364 success_message.slideDown();
1365 setTimeout(function() {
1366 window.location.reload();
1367 }, 500);
1368 }
1369
1370 $('#wpo_import_settings_btn').prop('disabled', false);
1371 });
1372 }
1373
1374 /*
1375 * Hide file validation message on change file field value.
1376 */
1377 $('#wpo_import_settings_file').on('change', function() {
1378 $('#wpo_import_error_message').slideUp();
1379 });
1380
1381 /*
1382 * Save settings to hidden form field, used for export.
1383 */
1384 $('#wpo_export_settings_btn').on('click', function(e) {
1385 wpo_download_json_file(gather_settings('object'));
1386 return false;
1387 });
1388
1389 /**
1390 * Force download json file with posted data.
1391 *
1392 * @param {Object} data data to put in a file.
1393 * @param {string} filename
1394 *
1395 * @return {void}
1396 */
1397 function wpo_download_json_file(data ,filename) {
1398 // Attach this data to an anchor on page
1399 var link = document.body.appendChild(document.createElement('a')),
1400 date = new Date(),
1401 year = date.getFullYear(),
1402 month = date.getMonth() < 10 ? ['0', date.getMonth()].join('') : date.getMonth(),
1403 day = date.getDay() < 10 ? ['0', date.getDay()].join('') : date.getDay();
1404
1405 filename = filename ? filename : ['wpo-settings-',year,'-',month,'-',day,'.json'].join('');
1406
1407 link.setAttribute('download', filename);
1408 link.setAttribute('style', "display:none;");
1409 link.setAttribute('href', 'data:text/json' + ';charset=UTF-8,' + encodeURIComponent(JSON.stringify(data)));
1410 link.click();
1411 }
1412
1413 /**
1414 * Make ajax request to get optimization info.
1415 *
1416 * @param {Object} optimization_info_container - jquery object obtimization info container.
1417 * @param {string} optimization_id - optimization id.
1418 * @param {Object} params - custom params posted to optimization get info.
1419 *
1420 * @return void
1421 */
1422 var optimization_get_info = function(optimization_info_container, optimization_id, params) {
1423 return send_command('get_optimization_info', {optimization_id: optimization_id, data: params}, function(resp) {
1424 var meta = (resp && resp.result && resp.result.meta) ? resp.result.meta : {},
1425 message = (resp && resp.result && resp.result.output) ? resp.result.output.join('<br>') : '...';
1426
1427 // trigger event about optimization get info in process.
1428 $(document).trigger(['optimization_get_info_', optimization_id].join(''), [message, meta]);
1429 // update status message in optimizations list.
1430 optimization_info_container.html(message);
1431
1432 if (!meta.finished) {
1433 setTimeout(function() {
1434 var xhr = optimization_get_info(optimization_info_container, optimization_id, meta);
1435 $(document).trigger(['optimization_get_info_xhr_', optimization_id].join(''), [xhr, meta]);
1436 }, 1);
1437 } else {
1438 // trigger event about optimization get info action done.
1439 $(document).trigger(['optimization_get_info_', optimization_id, '_done'].join(''), resp);
1440 }
1441 });
1442 };
1443
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 // attach event handlers after database tables template loaded.
1462 // Handle single optimization click.
1463 $('#wpoptimize_table_list').on('click', '.run-single-table-optimization', function () {
1464 var take_backup_checkbox = $('#enable-auto-backup-1'),
1465 button = $(this);
1466
1467 // check if backup checkbox is checked for db tables
1468 if (take_backup_checkbox.is(':checked')) {
1469 take_a_backup_with_updraftplus(
1470 function () {
1471 run_single_table_optimization(button);
1472 }
1473 );
1474 } else {
1475 run_single_table_optimization(button);
1476 }
1477 });
1478
1479 // Handle repair table click
1480 $('#wpoptimize_table_list').on('click', '.run-single-table-repair', function () {
1481 var btn = $(this),
1482 spinner = btn.next(),
1483 action_done_icon = spinner.next(),
1484 table_name = btn.data('table'),
1485 data = {
1486 optimization_id: 'repairtables',
1487 optimization_table: table_name
1488 };
1489
1490 spinner.removeClass('visibility-hidden');
1491
1492 send_command('do_optimization', {optimization_id: 'repairtables', data: data}, function (response) {
1493 if (response.result.meta.success) {
1494 var row = btn.closest('tr'),
1495 tableinfo = response.result.meta.tableinfo;
1496
1497 btn.prop('disabled', false);
1498 spinner.addClass('visibility-hidden');
1499 action_done_icon.show().removeClass('visibility-hidden');
1500
1501 update_single_table_information(row, tableinfo);
1502
1503 // keep visible results from previous operation for one second and show optimize button if possible.
1504 setTimeout(function () {
1505 var parent_td = btn.closest('td'),
1506 btn_wrap = btn.closest('.wpo_button_wrap');
1507
1508 // remove Repair button and show Optimize button.
1509 btn_wrap.fadeOut('fast', function () {
1510 btn_wrap.closest('.wpo_button_wrap').remove();
1511
1512 // if table type is supported for optimization then show OPTIMIZE button.
1513 if (tableinfo.is_type_supported) {
1514 $('.wpo_button_wrap', parent_td).removeClass('wpo_hidden');
1515 }
1516 });
1517
1518 change_actions_column_visibility();
1519 }, 1000);
1520 } else {
1521 btn.prop('disabled', false);
1522 spinner.addClass('visibility-hidden');
1523 alert(wpoptimize.table_was_not_repaired.replace('%s', table_name));
1524 }
1525 });
1526 });
1527
1528 // Handle convert table click
1529 $('#wpoptimize_table_list').on('click', '.toinnodb', function () {
1530 convert_single_db_table($(this));
1531 });
1532
1533 var table_to_remove_btn;
1534
1535 // Handle delete table click
1536 $('#wpoptimize_table_list').on('click', '.run-single-table-delete', function () {
1537 table_to_remove_btn = $(this);
1538 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) {
1540 wp_optimize.modal.open({
1541 className: 'wpo-confirm',
1542 events: {
1543 'click .wpo-modal--bg': 'close',
1544 'click .delete-table': 'deleteTable',
1545 'change #confirm_deletion_without_backup': 'changeConfirm',
1546 'change #confirm_table_deletion': 'changeConfirm'
1547 },
1548 content: function() {
1549 var content_template = wp.template('wpo-table-delete');
1550 // Get the plugins list
1551 var plugins_list = table_to_remove_btn.closest('tr').find('.table-plugins').html();
1552 return content_template({
1553 no_backup: !take_backup_checkbox.is(':checked'),
1554 plugins_list: plugins_list,
1555 table_name: table_to_remove_btn.data('table')
1556 });
1557 },
1558 changeConfirm: function() {
1559 var enable_button = true;
1560 var backup_input = this.$('#confirm_deletion_without_backup');
1561 var confirm_input = this.$('#confirm_table_deletion');
1562 if (backup_input.length && !backup_input.is(':checked')) {
1563 enable_button = false;
1564 }
1565 if (!confirm_input.is(':checked')) {
1566 enable_button = false;
1567 }
1568 this.$('.delete-table').prop('disabled', !enable_button);
1569 },
1570 deleteTable: function() {
1571 // 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) {
1575 if (response.success) {
1576 wpoptimize.user_always_ignores_table_delete_warning = '1';
1577 }
1578 });
1579 }
1580 // check if backup checkbox is checked for db tables
1581 if (take_backup_checkbox.is(':checked')) {
1582 take_a_backup_with_updraftplus(remove_single_db_table);
1583 } else {
1584 remove_single_db_table();
1585 }
1586 this.close();
1587
1588 }
1589 });
1590 } else {
1591 // check if backup checkbox is checked for db tables
1592 if (take_backup_checkbox.is(':checked')) {
1593 take_a_backup_with_updraftplus(remove_single_db_table);
1594 } else {
1595 remove_single_db_table();
1596 }
1597 }
1598 });
1599
1600 /**
1601 * Send ajax command to convert single table to InnoDB.
1602 *
1603 * @param {Object} btn jQuery object of clicked "Convert to InnoDB" button.
1604 *
1605 * @return void
1606 */
1607 function convert_single_db_table(table_to_convert_btn) {
1608 var spinner = table_to_convert_btn.next(),
1609 action_done_icon = spinner.next(),
1610 table_name = table_to_convert_btn.data('table'),
1611 data = {
1612 optimization_id: 'orphanedtables',
1613 optimization_table: table_name,
1614 optimization_action: 'toinnodb'
1615 };
1616
1617 spinner.removeClass('visibility-hidden');
1618
1619 send_command('do_optimization', { optimization_id: 'orphanedtables', data: data }, function (response) {
1620 if (response.result.meta.error) {
1621 table_to_convert_btn.closest('tr').html('<td colspan="8" class="no-table"><p>' + response.result.meta.message + '</p></td>');
1622 setTimeout(function() {
1623 $('#wp_optimize_table_list_refresh').trigger('click');
1624 }, 2000);
1625 return;
1626 }
1627 if (response.result.meta.success) {
1628 var row = table_to_convert_btn.closest('tr');
1629
1630 action_done_icon.show().removeClass('visibility-hidden');
1631
1632 // remove convert to Innodb button.
1633 row.find(".toinnodb").remove();
1634
1635
1636 setTimeout(function() {
1637 action_done_icon.fadeOut('slow', function() {
1638 row.find("[data-colname='Type']").text("InnoDB");
1639 });
1640 }, 500);
1641 } else {
1642 var message = wpoptimize.table_was_not_converted.replace('%s', table_name);
1643
1644 if (response.result.meta.message) {
1645 message += '(' + response.result.meta.message + ')';
1646 }
1647
1648 alert(message);
1649 }
1650 }).always(function() {
1651 table_to_convert_btn.prop('disabled', false);
1652 spinner.addClass('visibility-hidden');
1653 });
1654 }
1655
1656
1657
1658 /**
1659 * Send ajax commant to remove single database table.
1660 *
1661 * @param {Object} btn jQuery object of clicked "Remove" button.
1662 *
1663 * @return void
1664 */
1665 function remove_single_db_table() {
1666 var spinner = table_to_remove_btn.next(),
1667 action_done_icon = spinner.next(),
1668 table_name = table_to_remove_btn.data('table'),
1669 data = {
1670 optimization_id: 'orphanedtables',
1671 optimization_table: table_name
1672 };
1673
1674 spinner.removeClass('visibility-hidden');
1675
1676 send_command('do_optimization', { optimization_id: 'orphanedtables', data: data }, function (response) {
1677 if (response.result.meta.success) {
1678 var row = table_to_remove_btn.closest('tr');
1679
1680 action_done_icon.show().removeClass('visibility-hidden');
1681
1682 // remove row for deleted table.
1683 setTimeout(function() {
1684 row.fadeOut('slow', function() {
1685 row.remove();
1686
1687 change_actions_column_visibility();
1688 });
1689 }, 500);
1690 } else {
1691 var message = wpoptimize.table_was_not_deleted.replace('%s', table_name);
1692
1693 if (response.result.meta.message) {
1694 message += '(' + response.result.meta.message + ')';
1695 }
1696
1697 alert(message);
1698 }
1699 }).always(function() {
1700 table_to_remove_btn.prop('disabled', false);
1701 spinner.addClass('visibility-hidden');
1702 });
1703 }
1704
1705 change_actions_column_visibility();
1706
1707 /**
1708 * Show or hide actions column if need.
1709 *
1710 * @return void
1711 */
1712 function change_actions_column_visibility() {
1713 var table = $('#wpoptimize_table_list'),
1714 hideLastColumn = true;
1715
1716 // check if any button exists in the actions column.
1717 $('tr', table).each(function() {
1718 var row = $(this);
1719
1720 if ($('button', row).length > 0) {
1721 hideLastColumn = false;
1722 return false;
1723 }
1724 });
1725
1726 // hide or show last column
1727 $('tr', table).each(function() {
1728 var row = $(this);
1729
1730 if (hideLastColumn) {
1731 $('td:last, th:last', row).hide();
1732 } else {
1733 $('td:last, th:last', row).show();
1734 }
1735 });
1736 }
1737
1738 /*
1739 * Validate general settings (loggers).
1740 */
1741 $('#wp-optimize-general-settings').on('wpo-saving-form-data', function() {
1742 var valid = true;
1743 var $form = $(this);
1744
1745 $('.wpo_logger_addition_option, .wpo_logger_type').each(function() {
1746 if (!validate_field($(this), true)) {
1747 valid = false;
1748 $(this).addClass('wpo_error_field');
1749 } else {
1750 $(this).removeClass('wpo_error_field');
1751 }
1752 });
1753
1754 if (!valid) {
1755 $form.form_errors.add('missing-fields', '');
1756 $('#wp-optimize-settings-save-results')
1757 .show()
1758 .addClass('wpo_alert_notice')
1759 .text(wpoptimize.fill_all_settings_fields)
1760 .delay(5000)
1761 .fadeOut(3000, function() {
1762 $(this).removeClass('wpo_alert_notice');
1763 });
1764 } else {
1765 $form.form_errors.remove('missing-fields');
1766 $('#wp-optimize-logger-settings .save_settings_reminder').slideUp();
1767 }
1768
1769 });
1770
1771 /**
1772 * Validate import field with data-validate attribute.
1773 *
1774 * @param {object} field jquery element
1775 * @param {boolean} required
1776 *
1777 * @return {boolean}
1778 */
1779 function validate_field(field, required) {
1780 var value = field.val(),
1781 validate = field.data('validate');
1782
1783 if (!validate && required) {
1784 return ('' != $.trim(value));
1785 }
1786
1787 if (validate && !required && '' == $.trim(value)) {
1788 return true;
1789 }
1790
1791 var valid = true;
1792
1793 switch (validate) {
1794 case 'email':
1795 var regex = /\S+@\S+\.\S+/,
1796 emails = value.split(","),
1797 email = '';
1798
1799 for (var i = 0; i < emails.length; i++) {
1800 email = $.trim(emails[i]);
1801
1802 if ('' == email || !regex.test(email)) {
1803 valid = false;
1804 }
1805 }
1806 break;
1807
1808 case 'url':
1809 // https://gist.github.com/dperini/729294
1810 // @codingStandardsIgnoreLine
1811 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;
1812
1813 valid = regex.test(value);
1814 break;
1815 }
1816
1817 return valid;
1818 }
1819
1820 /**
1821 * Send check_overdue_crons command and output warning if need.
1822 */
1823 setTimeout(function() {
1824 send_command('check_overdue_crons', null, function (resp) {
1825 if (resp && resp.hasOwnProperty('m')) {
1826 $('#wpo_settings_warnings').append(resp.m);
1827 }
1828 });
1829 }, 11000);
1830
1831 /**
1832 * Hide introduction notice
1833 */
1834 $('.wpo-introduction-notice .notice-dismiss, .wpo-introduction-notice .close').on('click', function(e) {
1835 $('.wpo-introduction-notice').remove();
1836 send_command('dismiss_install_or_update_notice', null, function (resp) {
1837 if (resp && resp.hasOwnProperty('error')) {
1838 // there was an error.
1839 console.log('There was an error dismissing the install or update notice (dismiss_install_or_update_notice)', resp);
1840 }
1841 });
1842 });
1843
1844 return {
1845 send_command: send_command,
1846 optimization_get_info: optimization_get_info,
1847 take_a_backup_with_updraftplus: take_a_backup_with_updraftplus,
1848 save_auto_backup_options: save_auto_backup_options
1849 }
1850 }; // END function WP_Optimize()
1851
1852 jQuery(function ($) {
1853 /**
1854 * Show additional options section if optimization enabled
1855 *
1856 * @param {string} checkbox Logger settings jQuery checkbox object.
1857 *
1858 * @return {void}
1859 */
1860 function show_hide_additional_logger_options($checkbox) {
1861 var additional_section_id = ['#', $checkbox.data('additional')].join('');
1862
1863 if ($checkbox.is(':checked')) {
1864 $(additional_section_id).show();
1865 } else {
1866 $(additional_section_id).hide();
1867 }
1868 }
1869
1870 // Add events handler for each logger.
1871 $('.wp-optimize-logging-settings').each(function () {
1872 var $checkbox = $(this);
1873 show_hide_additional_logger_options($checkbox);
1874 $checkbox.on('change', function () {
1875 show_hide_additional_logger_options($checkbox);
1876 });
1877 });
1878
1879 var add_logging_btn = $('#wpo_add_logger_link');
1880
1881 /**
1882 * Handle add logging destination click.
1883 */
1884 add_logging_btn.on('click', function(e) {
1885 e.preventDefault();
1886 $('#wp-optimize-logger-settings .save_settings_reminder').after(get_add_logging_form_html());
1887
1888 filter_select_destinations($('.wpo_logger_type').first());
1889 });
1890
1891 /**
1892 * Handle logging destination select change.
1893 */
1894 $('#wp-optimize-general-settings').on('change', '.wpo_logger_type', function() {
1895 var select = $(this),
1896 logger_id = select.val(),
1897 options_container = select.parent().find('.wpo_additional_logger_options');
1898
1899 options_container.html(get_logging_additional_options_html(logger_id));
1900
1901 if (select.val()) {
1902 show_logging_save_settings_reminder();
1903 }
1904 });
1905
1906 /**
1907 * Show save settings reminder for logging settings.
1908 *
1909 * @return {void}
1910 */
1911 function show_logging_save_settings_reminder() {
1912 var reminder = $('#wp-optimize-logger-settings .save_settings_reminder');
1913
1914 if (!reminder.is(':visible')) {
1915 reminder.slideDown('normal');
1916 }
1917 }
1918
1919 /**
1920 * Handle edit logger click.
1921 */
1922 $('.wpo_logging_actions_row .dashicons-edit').on('click', function() {
1923
1924 var link = $(this),
1925 container = link.closest('.wpo_logging_row');
1926
1927 $('.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();
1931
1932 return false;
1933 });
1934
1935 $('#wp-optimize-logger-settings').on('change', '.wpo_logger_addition_option', function() {
1936 show_logging_save_settings_reminder();
1937 });
1938
1939 /**
1940 * Handle change of active/inactive status and update hidden field value.
1941 */
1942 $('.wpo_logger_active_checkbox').on('change', function() {
1943 var checkbox = $(this),
1944 hidden_input = checkbox.closest('label').find('input[type="hidden"]');
1945
1946 hidden_input.val(checkbox.is(':checked') ? '1' : '0');
1947 });
1948
1949 /**
1950 * Handle delete logger destination click.
1951 */
1952 $('#wp-optimize-general-settings').on('click', '.wpo_delete_logger', function() {
1953
1954 if (!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination)) {
1955 return false;
1956 }
1957
1958 var btn = $(this);
1959 btn.closest('.wpo_logging_row, .wpo_add_logger_form').remove();
1960 filter_all_select_destinations();
1961
1962 if (0 == $('#wp-optimize-logging-options .wpo_logging_row').length) {
1963 $('#wp-optimize-logging-options').hide();
1964 }
1965
1966 show_logging_save_settings_reminder();
1967
1968 return false;
1969 });
1970
1971 /**
1972 * Filter all selects with logger destinations, called after some destination deleted.
1973 *
1974 * @return {void}
1975 */
1976 function filter_all_select_destinations() {
1977 $('.wpo_logger_type').each(function() {
1978 filter_select_destinations($(this));
1979 });
1980 }
1981
1982 /**
1983 * Filter certain select options depending on currently selected values.
1984 *
1985 * @param {object} select
1986 *
1987 * @return {void}
1988 */
1989 function filter_select_destinations(select) {
1990 var i,
1991 destination,
1992 current_destinations = get_current_destinations();
1993
1994 for (i in current_destinations) {
1995 destination = current_destinations[i];
1996 if (wpoptimize.loggers_classes_info[destination].allow_multiple) {
1997 $('option[value="'+destination+'"]', select).show();
1998 } else {
1999 $('option[value="'+destination+'"]', select).hide();
2000 }
2001 }
2002 }
2003
2004 /**
2005 * Returns currently selected loggers destinations.
2006 *
2007 * @return {Array}
2008 */
2009 function get_current_destinations() {
2010 var destinations = [];
2011
2012 $('.wpo_logging_row, .wpo_logger_type').each(function() {
2013 var destination = $(this).is('select') ? $(this).val() : $(this).data('id');
2014
2015 if (destination) destinations.push(destination);
2016 });
2017
2018 return destinations;
2019 }
2020
2021 /**
2022 * Return add logging form.
2023 *
2024 * @return {string}
2025 */
2026 function get_add_logging_form_html() {
2027 var i,
2028 select_options = [
2029 '<option value="">Select destination</option>'
2030 ];
2031
2032 for (i in wpoptimize.loggers_classes_info) {
2033 if (!wpoptimize.loggers_classes_info.hasOwnProperty(i)) continue;
2034
2035 if (!wpoptimize.loggers_classes_info[i].available) continue;
2036
2037 select_options.push(['<option value="',i,'">',wpoptimize.loggers_classes_info[i].description,'</option>'].join(''));
2038 }
2039
2040 return [
2041 '<div class="wpo_add_logger_form">',
2042 '<select class="wpo_logger_type" name="wpo-logger-type[]">',
2043 select_options.join(''),
2044 '<select>',
2045 '<a href="#" class="wpo_delete_logger dashicons dashicons-no-alt"></a>',
2046 '<div class="wpo_additional_logger_options"></div>',
2047 '</div>'
2048 ].join('');
2049 }
2050
2051 /**
2052 * Returns logging options html.
2053 *
2054 * @param {string} logger_id
2055 *
2056 * @return {string}
2057 */
2058 function get_logging_additional_options_html(logger_id) {
2059 if (!wpoptimize.loggers_classes_info[logger_id].options) return '';
2060
2061 var i,
2062 options = wpoptimize.loggers_classes_info[logger_id].options,
2063 options_list = [],
2064 placeholder = '',
2065 validate = '';
2066
2067 for (i in options) {
2068 if (!options.hasOwnProperty(i)) continue;
2069
2070 if (Array.isArray(options[i])) {
2071 placeholder = $.trim(options[i][0]);
2072 validate = $.trim(options[i][1]);
2073 } else {
2074 placeholder = $.trim(options[i]);
2075 validate = '';
2076 }
2077
2078 options_list.push([
2079 '<input class="wpo_logger_addition_option" type="text" name="wpo-logger-options[',i,'][]" value="" ',
2080 'placeholder="',placeholder,'" ',('' !== validate ? 'data-validate="'+validate+'"' : ''), '/>'
2081 ].join(''));
2082 }
2083
2084 // Add hidden field for active/inactive value.
2085 options_list.push('<input type="hidden" name="wpo-logger-options[active][]" value="1" />');
2086
2087 return options_list.join('');
2088 }
2089
2090 /**
2091 * Layout - Adds `is-scrolled` class to the body element when scrolled.
2092 */
2093 var is_scrolled = false;
2094 $(window).on('scroll', function(e) {
2095 window.requestAnimationFrame(function() {
2096 var threshold = $('.wpo-main-header').length ? $('.wpo-main-header')[0].offsetTop : 0;
2097 if ((window.pageYOffset > threshold - 20) != is_scrolled) {
2098 is_scrolled = !is_scrolled;
2099 $('body').toggleClass('is-scrolled', is_scrolled);
2100 }
2101 });
2102 });
2103
2104 // Opens the video preview / info popup
2105 $('.wpo-info__trigger').on('click', function(e) {
2106 e.preventDefault();
2107 var $container = $(this).closest('.wpo-info');
2108 $container.toggleClass('opened');
2109 });
2110
2111 // Embed videos when clicking the vimeo links
2112 $('.wpo-video-preview a').on('click', function(e) {
2113 var video_url = $(this).data('embed');
2114 if (video_url) {
2115 e.preventDefault();
2116 var $iframe = $('<iframe width="356" height="200" allowfullscreen webkitallowfullscreen mozallowfullscreen>').attr('src', video_url);
2117 $iframe.insertAfter($(this));
2118 $(this).remove();
2119 $iframe.focus();
2120 }
2121 });
2122 });
2123