PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
mainwp / assets / js / mainwp.js

mainwp.js in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.1, at assets/js/mainwp.js

5,728 lines 232.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* eslint-disable complexity */
2 // current complexity is the only way to achieve desired results, pull request solutions appreciated.
3
4 globalThis.mainwpVars = globalThis.mainwpVars || {};
5
6 jQuery(function ($) {
7
8 if (jQuery('.mainwp-ui-page').length) {
9 jQuery('.mainwp-popup-tooltip').popup()
10 }
11
12 jQuery(document).on('click', '#mainwp-help-menu-item, #mainwp-help-menu-item-mobile', function () {
13 jQuery('#mainwp-help-modal').modal({
14 inverted: true,
15 blurring: false,
16 closable: false,
17 onShow: function () {
18 jQuery('#mainwp-help-modal').parent('.ui.dimmer').removeClass('dimmer');
19 jQuery('#mainwp-help-modal').css({
20 'top': (jQuery(globalThis).height() - jQuery('#mainwp-help-modal').outerHeight()) / 2 + 'px',
21 'left': (jQuery(globalThis).width() - jQuery('#mainwp-help-modal').outerWidth()) / 2 + 'px'
22 });
23 },
24
25 }).modal('show').draggable().resizable({
26 handles: "n, e, s, w, ne, nw, se, sw", // Allows resizing from all edges
27 minWidth: 300, // Set minimum width
28 minHeight: 640, // Set minimum height
29 });
30 return false;
31 });
32
33 // review for new UI update
34 jQuery(document).on('click', '#mainwp-category-add-submit', function () {
35 let newCat = jQuery('#newcategory').val();
36 newCat = encodeURIComponent(newCat).replaceAll('%20', ' ');
37
38 if (jQuery('#categorychecklist .menu').find('.item[data-value="' + newCat + '"]').length > 0) {
39 jQuery('#newcategory').val('');
40 return;
41 }
42 let selected_categories = jQuery('#categorychecklist').dropdown('get value');
43 jQuery('#categorychecklist .menu').append('<div class="item" data-value="' + newCat + '">' + newCat + '</div>');
44 jQuery('#categorychecklist .menu').dropdown('set selected', selected_categories); // to refresh.
45 jQuery('#newcategory').val('');
46 });
47
48 // Show/Hide new category field and button
49 jQuery(document).on('click', '#category-add-toggle', function () {
50 jQuery('#newcategory-field').toggle();
51 jQuery('#mainwp-category-add-submit-field').toggle();
52 return false;
53 });
54
55 // Manage Child options
56 $('.mainwp-parent-toggle input[type="checkbox"]').on('change', function () {
57 if (this.checked) {
58 $(this).closest('.mainwp-parent-toggle').next('.mainwp-child-field').fadeIn();
59 } else {
60 $(this).closest('.mainwp-parent-toggle').next('.mainwp-child-field').fadeOut();
61 }
62 });
63
64 //Toggle Add Site form
65 jQuery('#mainwp_managesites_verify_installed_child').on('change', function () {
66 if (jQuery(this).is(':checked')) {
67 jQuery('#mainwp-add-site-hidden-form').fadeIn(500);
68 } else {
69 jQuery('#mainwp-add-site-hidden-form').fadeOut(500);
70 }
71 });
72
73 // Toggle Add Site / Optional Settings section
74 jQuery('#mainwp-add-site-advanced-options-toggle').on('click', function () {
75 jQuery('#mainwp-add-site-advanced-options').toggle(500);
76 return false;
77 });
78
79 jQuery('.mainwp-remove-site-button').on('click', function () {
80 let side_id = jQuery(this).attr('site-id');
81 let confirmation = "Are you sure you want to remove this site from your MainWP Dashboard?";
82
83 let _confirm_callback = mainwp_get_remove_calback(side_id);
84
85 mainwp_confirm(confirmation, _confirm_callback, false, false, false, 'REMOVE');
86
87 return false;
88 });
89
90 });
91
92 let mainwp_get_remove_calback = function (side_id) {
93 return function () {
94 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Removing the site. Please wait...'), '');
95 let data = mainwp_secure_data({
96 action: 'mainwp_removesite',
97 id: side_id
98 });
99
100 jQuery.ajax({
101 url: ajaxurl,
102 data: data,
103 timeout: 180000, // 3 minutes. Slightly longer than the PHP server timeout (2 minutes).
104 method: 'POST',
105 success: function (response) {
106
107 const removed_site = response?.removed_site ?? false;
108 let msg_not_removed = MainWP.I18n.t('Site could not be removed. Please reload the page and try again.');
109
110 let error_msg = '';
111
112 if (typeof response?.error === 'string' && response.error.trim() !== '') {
113 error_msg = MainWP.I18n.t('Details:') + ' ' + response.error;
114 msg_not_removed += ' ' + error_msg;
115 }
116
117 if (response?.undefined_error) {
118 if (!removed_site) {
119 feedback(
120 'mainwp-message-zone',
121 msg_not_removed,
122 'red'
123 );
124 return;
125 }
126 feedback(
127 'mainwp-message-zone',
128 MainWP.I18n.t('The site has been removed. Please make sure that the MainWP Child plugin has been deactivated properly. You will be redirected to the Sites page right away.'),
129 'red'
130 );
131 } else if (!removed_site) {
132 feedback(
133 'mainwp-message-zone',
134 msg_not_removed,
135 'red'
136 );
137 return;
138 } else if (response?.error) {
139 let message = MainWP.I18n.t('The site has been removed. Please make sure that the MainWP Child plugin has been deactivated properly. You will be redirected to the Sites page right away.');
140 if (error_msg) {
141 message += ' ' + error_msg;
142 }
143 feedback('mainwp-message-zone', message, 'red');
144 } else {
145 switch (response?.result) {
146 case 'SUCCESS':
147 feedback(
148 'mainwp-message-zone',
149 MainWP.I18n.t('The site has been removed and the MainWP Child plugin has been disabled. You will be redirected to the Sites page right away.'),
150 'green'
151 );
152 break;
153 case 'REMOVED': // for demo sites.
154 feedback(
155 'mainwp-message-zone',
156 MainWP.I18n.t('The site has been removed. You will be redirected to the Sites page right away.'),
157 'green'
158 );
159 break;
160 case 'NOSITE':
161 feedback(
162 'mainwp-message-zone',
163 msg_not_removed,
164 'red'
165 );
166 return;
167 default:
168 feedback(
169 'mainwp-message-zone',
170 MainWP.I18n.t('The site has been removed. Please make sure that the MainWP Child plugin has been deactivated properly. You will be redirected to the Sites page right away.'),
171 'green'
172 );
173 }
174 }
175 setTimeout(function () {
176 mainwp_forceReload('admin.php?page=managesites');
177 }, 3000);
178 },
179 error: function (xhr, textStatus) {
180 if (textStatus === 'timeout') {
181 feedback(
182 'mainwp-message-zone',
183 MainWP.I18n.t('The request timed out. Please make sure that the MainWP Child plugin has been deactivated properly.'),
184 'red'
185 );
186 return;
187 }
188
189 feedback(
190 'mainwp-message-zone',
191 MainWP.I18n.t('An unexpected error occurred. Please reload the page and try again.'),
192 'red'
193 );
194 },
195 dataType: 'json'
196 });
197 }
198
199 }
200
201 globalThis.mainwp_set_message_zone = globalThis.mainwp_set_message_zone || function (zone_selector, msg_html, colors, show) {
202 if (msg_html) {
203 jQuery(zone_selector).html(msg_html);
204 } else if (msg_html === '' || msg_html === undefined) {
205 jQuery(zone_selector).html('');
206 }
207
208 if (colors !== undefined && colors != '') {
209 jQuery(zone_selector).removeClass('green yellow red');
210 jQuery(zone_selector).addClass(colors);
211 } else if (colors === '' || colors === undefined) {
212 jQuery(zone_selector).removeClass('green yellow red');
213 }
214
215 if (true === show || (false !== show && msg_html)) {
216 jQuery(zone_selector).show();
217 } else {
218 jQuery(zone_selector).hide();
219 }
220 };
221
222 let bulkInstallMaxThreads = mainwpParams['maximumInstallUpdateRequests'] == undefined ? 3 : mainwpParams['maximumInstallUpdateRequests'];
223 let bulkInstallCurrentThreads = 0;
224 let bulkInstallDone = 0;
225
226 /**
227 * Global
228 */
229 jQuery(function () {
230 jQuery('.mainwp-row').on({
231 mouseenter: function () {
232 rowMouseEnter(this);
233 },
234 mouseleave: function () {
235 rowMouseLeave(this);
236 }
237 });
238 });
239 let rowMouseEnter = function (elem) {
240 if (!jQuery(elem).children('.mainwp-row-actions-working').is(":visible"))
241 jQuery(elem).children('.mainwp-row-actions').show();
242 };
243 let rowMouseLeave = function (elem) {
244 if (jQuery(elem).children('.mainwp-row-actions').is(":visible"))
245 jQuery(elem).children('.mainwp-row-actions').hide();
246 };
247
248 /**
249 * Recent posts
250 */
251 jQuery(function () {
252 jQuery(document).on('click', '.mainwp-post-unpublish', function () {
253 postAction(jQuery(this), 'unpublish');
254 return false;
255 });
256 jQuery(document).on('click', '.mainwp-post-publish', function () {
257 postAction(jQuery(this), 'publish');
258 return false;
259 });
260 jQuery(document).on('click', '.mainwp-post-trash', function () {
261 postAction(jQuery(this), 'trash');
262 return false;
263 });
264 jQuery(document).on('click', '.mainwp-post-restore', function () {
265 postAction(jQuery(this), 'restore');
266 return false;
267 });
268 jQuery(document).on('click', '.mainwp-post-delete', function () {
269 postAction(jQuery(this), 'delete');
270 return false;
271 });
272
273 });
274
275 // Publish, Unpublish, Trash, ... posts and pages
276 let postAction = function (elem, what) {
277 let rowElement = jQuery(elem).closest('.grid');
278 let postId = rowElement.children('.postId').val();
279 let websiteId = rowElement.children('.websiteId').val();
280
281 let data = mainwp_secure_data({
282 action: 'mainwp_post_' + what,
283 postId: postId,
284 websiteId: websiteId
285 });
286 rowElement.hide();
287 rowElement.next('.mainwp-row-actions-working').show();
288 jQuery.post(ajaxurl, data, function (response) {
289 if (response.error) {
290 rowElement.show();
291 rowElement.next('.mainwp-row-actions-working').hide();
292 rowElement.html('<div class="sixteen wide column"><i class="times red icon"></i> ' + response.error + '</div>');
293 } else if (response.result) {
294 rowElement.show();
295 rowElement.next('.mainwp-row-actions-working').hide();
296 rowElement.html('<div class="sixteen wide column"><i class="check green icon"></i>' + response.result + '</div>');
297 } else {
298 rowElement.show();
299 rowElement.next('.mainwp-row-actions-working').hide();
300 }
301 }, 'json');
302 return false;
303 };
304
305
306 let mainwp_post_posting_start_next = function (start) {
307 if (start !== undefined && start) {
308 bulkInstallDone = 0;
309 bulkInstallCurrentThreads = 0;
310 mainwpVars.bulkInstallTotal = jQuery('.site-bulk-posting[status="queue"]').length;
311 }
312 while ((siteToPosting = jQuery('.site-bulk-posting[status="queue"]:first')) && (siteToPosting.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR -- modified out side the function.
313 mainwp_post_posting_start_specific(siteToPosting);
314 }
315 };
316
317 let mainwp_post_posting_start_specific = function (siteToPosting) {
318 siteToPosting.attr('status', 'progress');
319 bulkInstallDone++;
320 bulkInstallCurrentThreads++;
321 let data = mainwp_secure_data({
322 action: 'mainwp_post_postingbulk',
323 post_id: jQuery('#bulk_posting_id').val(),
324 site_id: jQuery(siteToPosting).attr('site-id'),
325 count: bulkInstallDone,
326 total: mainwpVars.bulkInstallTotal,
327 delete_bulkpost: (bulkInstallDone == mainwpVars.bulkInstallTotal)
328 });
329 siteToPosting.find('.progress').html('<i class="notched circle loading icon"></i>');
330 jQuery.post(ajaxurl, data, function (response) {
331 bulkInstallCurrentThreads--;
332 if (response?.result) {
333 siteToPosting.find('.progress').html(response.result);
334 if (response.edit_link !== '') {
335 siteToPosting.after(response.edit_link);
336 }
337 }
338 mainwp_post_posting_start_next();
339 }, 'json');
340 }
341
342
343 /**
344 * Plugins Widget
345 */
346 jQuery(function () {
347 jQuery(document).on('click', '.mainwp-plugin-deactivate', function () {
348 pluginAction(jQuery(this), 'deactivate');
349 return false;
350 });
351 jQuery(document).on('click', '.mainwp-plugin-activate', function () {
352 pluginAction(jQuery(this), 'activate');
353 return false;
354 });
355 jQuery(document).on('click', '.mainwp-plugin-delete', function () {
356 let name = jQuery(this).closest('.row-manage-item').attr('plugin-title');
357 let confirmMsg = MainWP.I18n.t('You are about to delete the %1?', name);
358 mainwp_confirm(confirmMsg, () => {
359 pluginAction(jQuery(this), 'delete');
360 });
361 return false;
362 });
363 });
364
365
366 let pluginAction = function (elem, what) {
367 let rowElement = jQuery(elem).closest('.row-manage-item');
368 let plugin = rowElement.children('.pluginSlug').val();
369 let websiteId = rowElement.children('.websiteId').val();
370
371 let data = mainwp_secure_data({
372 action: 'mainwp_widget_plugin_' + what,
373 plugin: plugin,
374 websiteId: websiteId
375 });
376 plugin_theme_doAction(data, rowElement);
377 return false;
378 };
379
380 /**
381 * Themes Widget
382 */
383 jQuery(function () {
384 jQuery(document).on('click', '.mainwp-theme-activate', function () {
385 themeAction(jQuery(this), 'activate');
386 return false;
387 });
388 jQuery(document).on('click', '.mainwp-theme-delete', function () {
389 let name = jQuery(this).closest('.row-manage-item').children('.themeName').val();
390 let confirmMsg = MainWP.I18n.t('You are about to delete the %1?', name);
391 mainwp_confirm(confirmMsg, () => {
392 themeAction(jQuery(this), 'delete');
393 });
394 return false;
395 });
396 });
397
398 let themeAction = function (elem, what) {
399 let rowElement = jQuery(elem).closest('.row-manage-item');
400 let theme = rowElement.children('.themeSlug').val();
401 let websiteId = rowElement.children('.websiteId').val();
402 let data = mainwp_secure_data({
403 action: 'mainwp_widget_theme_' + what,
404 theme: theme,
405 websiteId: websiteId
406 });
407 plugin_theme_doAction(data, rowElement);
408 return false;
409 };
410
411 let plugin_theme_doAction = function (data, rowElement) {
412 rowElement.children().hide();
413 rowElement.children('.mainwp-row-actions-working').show();
414 jQuery.post(ajaxurl, data, function (response) {
415 if (response?.error) {
416 rowElement.children().show();
417 rowElement.html(response.error);
418 } else if (response?.result) {
419 rowElement.children().show();
420 rowElement.html(response.result);
421 } else {
422 rowElement.children('.mainwp-row-actions-working').hide();
423 }
424 }, 'json');
425 };
426
427
428 // offsetRelative (or, if you prefer, positionRelative)
429 (function ($) {
430 $.fn.offsetRelative = function (top) {
431 let $this = $(this);
432 let $parent = $this.offsetParent();
433 let offset = $this.position();
434 if (!top)
435 return offset; // Didn't pass a 'top' element
436 else if ($parent.get(0).tagName == "BODY")
437 return offset; // Reached top of document
438 else if ($(top, $parent).length)
439 return offset; // Parent element contains the 'top' element we want the offset to be relative to
440 else if ($parent[0] == $(top)[0])
441 return offset; // Reached the 'top' element we want the offset to be relative to
442 else { // Get parent's relative offset
443 let parent_offset = $parent.offsetRelative(top);
444 offset.top += parent_offset.top;
445 offset.left += parent_offset.left;
446 return offset;
447 }
448 };
449 $.fn.positionRelative = function (top) {
450 return $(this).offsetRelative(top);
451 };
452 })(jQuery);
453
454 let hidingSubMenuTimers = {};
455 jQuery(function () {
456 jQuery('.mainwp-submenu-wrapper').on({
457 mouseenter: function () {
458 let spanId = /^menu-mainwp-(.*)$/.exec(jQuery(this).attr('id'));
459 if (spanId) {
460 if (hidingSubMenuTimers[spanId[1]]) {
461 clearTimeout(hidingSubMenuTimers[spanId[1]]);
462 }
463 }
464 },
465 mouseleave: function () {
466 let spanId = /^menu-mainwp-(.*)$/.exec(jQuery(this).attr('id'));
467 if (spanId) {
468 hidingSubMenuTimers[spanId[1]] = setTimeout(function (span) {
469 return function () {
470 subMenuOut(span);
471 };
472 }(spanId[1]), 30);
473 }
474 }
475 });
476 });
477 let subMenuOut = function (subName) {
478 jQuery('#menu-mainwp-' + subName).hide();
479 jQuery('#mainwp-' + subName).parent().parent().css('background-color', '');
480 jQuery('#mainwp-' + subName).parent().parent().removeClass('hoverli');
481 jQuery('#mainwp-' + subName).css('color', '');
482 };
483 // eslint-disable-next-line complexity
484 globalThis.mainwp_js_get_error_not_detected_connect = function (jsonStr, what, elemId, retErrText) { // NOSONAR - complexity.
485 if (undefined !== jsonStr && '' != jsonStr && undefined !== what && 'html_msg' === what) {
486 try {
487 let obj_err = JSON.parse(jsonStr);
488 if (typeof obj_err === 'object') {
489 if (obj_err?.el_before && obj_err?.el_link && obj_err?.el_text) {
490 let elafter = obj_err.el_after === undefined ? '' : obj_err.el_after;
491 if (true === retErrText) {
492 return obj_err.el_before + obj_err.el_text + elafter;
493 }
494 if (undefined !== elemId && '' != elemId) {
495 let el = document.createElement('a');
496 el.text = obj_err.el_text;
497 el.href = obj_err.el_link;
498 el.target = "_blank";
499 console.log(el);
500 jQuery('#' + elemId).html('').append(document.createTextNode(obj_err.el_before), el, document.createTextNode(elafter));
501 feedback_scroll(elemId, 'red');
502 }
503 return true;
504 }
505 } else {
506 return false; // it is not or invalid json.
507 }
508 } catch (e) {
509 console.log(e);
510 return false; // it is not or invalid json.
511 }
512 }
513 return MainWP.I18n.t('MainWP Child plugin not detected or could not be reached! Ensure the MainWP Child plugin is installed and activated on the child site, and there are no security rules blocking requests. If you continue experiencing this issue, check the MainWP Community for help.');
514 }
515
516 globalThis.mainwp_get_reconnect_error = function (response, siteId) { // NOSONAR - complexity.
517 if ('reconnect_failed' === response) {
518 return MainWP.I18n.t('Reconnect failed. Please try again from the %1Site Settings page%2.', '<a href="admin.php?page=managesites&id=' + siteId + '">', '</a>');
519 } else {
520 return response;
521 }
522 }
523
524 function shake_element(select) {
525 let pos = jQuery(select).position();
526 let type = jQuery(select).css('position');
527
528 if (type == 'static') {
529 jQuery(select).css({
530 position: 'relative'
531 });
532 }
533
534 if (type == 'static' || type == 'relative') {
535 pos.top = 0;
536 pos.left = 0;
537 }
538
539 jQuery(select).data('init-type', type);
540
541 let shake = [[0, 5, 60], [0, 0, 60], [0, -5, 60], [0, 0, 60], [0, 2, 30], [0, 0, 30], [0, -2, 30], [0, 0, 30]];
542
543 for (let s of shake) {
544 jQuery(select).animate({
545 top: pos.top + s[0],
546 left: pos.left + s[1]
547 }, s[2], 'linear');
548 }
549 }
550
551
552 /**
553 * Required
554 */
555 globalThis.feedback = function (id, text, type, append) {
556 if (append) {
557 let currentHtml = jQuery('#' + id).html();
558 if (currentHtml == null)
559 currentHtml = "";
560 if (currentHtml == '') {
561 currentHtml = text;
562 } else {
563 currentHtml += '<br />' + text;
564 }
565 jQuery('#' + id).html(currentHtml);
566 jQuery('#' + id).removeClass('yellow');
567 jQuery('#' + id).removeClass('green');
568 jQuery('#' + id).removeClass('red');
569 jQuery('#' + id).addClass(type);
570 } else {
571 jQuery('#' + id).html(text);
572 jQuery('#' + id).removeClass('yellow');
573 jQuery('#' + id).removeClass('green');
574 jQuery('#' + id).removeClass('red');
575 jQuery('#' + id).addClass(type);
576 }
577 jQuery('#' + id).show();
578
579 // automatically scroll to error message if it's not visible
580 scrollElementTop(id);
581 };
582
583 globalThis.feedback_scroll = function (id, color) {
584 jQuery('#' + id).removeClass('green red yellow');
585 jQuery('#' + id).addClass(color);
586 jQuery('#' + id).show();
587 // automatically scroll to error message if it's not visible
588 scrollElementTop(id);
589 }
590
591 globalThis.scrollElementTop = function (id) {
592 let scrolltop = jQuery(globalThis).scrollTop();
593 if (jQuery('#' + id).length == 0) {
594 return;
595 }
596 let off = jQuery('#' + id).offset();
597 if (scrolltop > off.top - 40)
598 jQuery('html, body').animate({
599 scrollTop: off.top - 40
600 }, 1000, function () {
601 shake_element('#' + id)
602 });
603 else
604 shake_element('#' + id); // shake the error message to get attention :)
605 }
606
607 globalThis.mainwp_showhide_message = function (id, content, cls, append, scroll) {
608
609 if ('' === content) {
610 jQuery('#' + id).html('').fadeOut(500);
611 return;
612 }
613
614 if (append) {
615 let html = jQuery('#' + id).html();
616 if (html == null)
617 html = "";
618 if (html == '') {
619 html = content;
620 } else {
621 html += '<br />' + content;
622 }
623 jQuery('#' + id).html(html);
624 } else {
625 jQuery('#' + id).html(content);
626 }
627
628 jQuery('#' + id).removeClass('yellow green red');
629 jQuery('#' + id).addClass(cls);
630 jQuery('#' + id).show();
631
632 if (scroll === undefined && scroll) {
633 scrollElementTop(id);
634 }
635
636 };
637
638 jQuery(function () {
639 jQuery('div.mainwp-hidden').parent().parent().css("display", "none");
640 });
641
642 /**
643 * Security Issues
644 */
645
646 let securityIssues_fixes = ['core_updates', 'plugin_updates', 'theme_updates', 'db_reporting', 'php_reporting', 'wp_uptodate', 'phpversion_matched', 'sslprotocol', 'debug_disabled', 'sec_outdated_plugins', 'sec_inactive_plugins', 'sec_outdated_themes', 'sec_inactive_themes'];
647 jQuery(function () {
648 let securityIssueSite = jQuery('#securityIssueSite');
649 if ((securityIssueSite.val() != null) && (securityIssueSite.val() != "")) {
650 jQuery(document).on('click', '#securityIssues_refresh', function () {
651 for (let ise of securityIssues_fixes) {
652 let securityIssueCurrentIssue = jQuery('#' + ise + '_fix');
653 if (securityIssueCurrentIssue) {
654 securityIssueCurrentIssue.hide();
655 }
656 jQuery('#' + ise + '_extra').hide();
657 jQuery('#' + ise + '_ok').hide();
658 jQuery('#' + ise + '_nok').hide();
659 jQuery('#' + ise + '_loading').show();
660 }
661 securityIssues_request(jQuery('#securityIssueSite').val());
662 });
663
664 for (let ise of securityIssues_fixes) {
665 if (ise === 'wp_uptodate' || ise === 'sec_inactive_themes' || ise === 'sec_inactive_plugins' || ise === 'sec_outdated_plugins' || ise === 'sec_outdated_themes') {
666 continue;
667 }
668 jQuery('#' + ise + '_fix').on('click', function (what) {
669 return function () {
670 securityIssues_fix(what);
671 return false;
672 }
673 }(ise));
674
675 jQuery('#' + ise + '_unfix').on('click', function (what) {
676 return function () {
677 securityIssues_unfix(what);
678 return false;
679 }
680 }(ise));
681 }
682 securityIssues_request(securityIssueSite.val());
683 }
684 });
685 globalThis.securityIssues_fix = function (feature) {
686 if (jQuery('#' + feature + '_fix')) {
687 jQuery('#' + feature + '_fix').hide();
688 }
689 jQuery('#' + feature + '_extra').hide();
690 jQuery('#' + feature + '_ok').hide();
691 jQuery('#' + feature + '_nok').hide();
692 jQuery('#' + feature + '_loading').show();
693
694 let data = mainwp_secure_data({
695 action: 'mainwp_security_issues_fix',
696 feature: feature,
697 id: jQuery('#securityIssueSite').val()
698 });
699
700 jQuery.post(ajaxurl, data, function (response) {
701 securityIssues_handle(response);
702 }, 'json');
703 };
704
705 let securityIssues_unfix = function (feature) {
706 if (jQuery('#' + feature + '_unfix')) {
707 jQuery('#' + feature + '_unfix').hide();
708 }
709 jQuery('#' + feature + '_extra').hide();
710 jQuery('#' + feature + '_ok').hide();
711 jQuery('#' + feature + '_nok').hide();
712 jQuery('#' + feature + '_loading').show();
713
714 let data = mainwp_secure_data({
715 action: 'mainwp_security_issues_unfix',
716 feature: feature,
717 id: jQuery('#securityIssueSite').val()
718 });
719 jQuery.post(ajaxurl, data, function (response) {
720 securityIssues_handle(response);
721 }, 'json');
722 };
723 let securityIssues_request = function (websiteId) {
724 let data = mainwp_secure_data({
725 action: 'mainwp_security_issues_request',
726 id: websiteId
727 });
728 jQuery.post(ajaxurl, data, function (response) {
729 securityIssues_handle(response);
730 }, 'json');
731 };
732 // eslint-disable-next-line complexity
733 let securityIssues_handle = function (response) { // NOSONAR - complex.
734 let result = '';
735 if (response.error) {
736 result = getErrorMessage(response.error);
737 } else {
738 try {
739 let res = response.result;
740 for (let issue in res) {
741 if (jQuery('#' + issue + '_loading')) {
742 jQuery('#' + issue + '_loading').hide();
743 if (res[issue] == 'Y' || res[issue] == 'Y_UNABLE') {
744 jQuery('#' + issue + '_extra').hide();
745 jQuery('#' + issue + '_nok').hide();
746 if (jQuery('#' + issue + '_fix')) {
747 jQuery('#' + issue + '_fix').hide();
748 }
749
750 if (jQuery('#' + issue + '_unfix')) {
751 jQuery('#' + issue + '_unfix').show();
752 if (res[issue] == 'Y_UNABLE') { // Y_UNABLE will disable unfix.
753 jQuery('#' + issue + '_unfix').hide();
754 }
755 }
756
757 jQuery('#' + issue + '_ok').show();
758 jQuery('#' + issue + '-status-ok').show();
759 jQuery('#' + issue + '-status-nok').hide();
760 } else if (res[issue] == 'N' || res[issue] == 'N_UNABLE') {
761 jQuery('#' + issue + '_extra').hide();
762 jQuery('#' + issue + '_ok').hide();
763 jQuery('#' + issue + '_nok').show();
764
765 if (jQuery('#' + issue + '_fix')) {
766 jQuery('#' + issue + '_fix').show();
767 if (res[issue] == 'N_UNABLE') { // N_UNABLE will disable fix.
768 jQuery('#' + issue + '_fix').hide().after('<a href="javascript:void(0);" class="ui mini fluid button" disabled="disabled">fix</a>');
769 }
770 }
771
772 if (jQuery('#' + issue + '_unfix')) {
773 jQuery('#' + issue + '_unfix').hide();
774 }
775 if (res[issue] != 'N') {
776 jQuery('#' + issue + '_extra').html(res[issue]);
777 jQuery('#' + issue + '_extra').show();
778 }
779
780 if ('wp_uptodate' === issue) {
781 jQuery('#wp_upgrades').find('div[updated="-1"]').each(function () {
782 jQuery(this).attr('updated', 0);
783 });
784 }
785 jQuery('#' + issue + '-status-ok').hide();
786 jQuery('#' + issue + '-status-nok').show();
787 }
788 }
789 }
790 } catch {
791 result = '<i class="exclamation circle icon"></i> ' + MainWP.I18n.t('Undefined error!');
792 }
793 }
794 if (result != '') {
795 //show error!
796 }
797 };
798
799 globalThis.updatesoverview_bulk_check_abandoned = function (which) {
800 let confirmMsg;
801 if ('plugin' == which) {
802 confirmMsg = MainWP.I18n.t("You are about to check abandoned plugins on the sites?");
803 } else {
804 confirmMsg = MainWP.I18n.t("You are about to check abandoned themes on the sites?");
805 }
806 mainwp_confirm(confirmMsg, function () { mainwp_managesites_bulk_check_abandoned('all', which); });
807 }
808
809 globalThis.mainwp_managesites_bulk_check_abandoned = function (siteIds, which) {
810 let allWebsiteIds = jQuery('.dashboard_wp_id[error-status=0]').map(function (indx, el) {
811 return jQuery(el).val();
812 });
813
814 if ('all' == siteIds) {
815 siteIds = allWebsiteIds;
816 }
817
818 let selectedIds = [], excludeIds = [];
819 if (Array.isArray(siteIds)) {
820 jQuery.grep(allWebsiteIds, function (el) {
821 if (jQuery.inArray(el, siteIds) === -1) {
822 excludeIds.push(el);
823 } else {
824 selectedIds.push(el);
825 }
826 });
827 for (let id of excludeIds) {
828 dashboard_update_site_hide(id);
829 }
830 allWebsiteIds = selectedIds;
831 }
832
833 let nrOfWebsites = allWebsiteIds.length;
834
835 if (nrOfWebsites == 0) {
836 managesites_reset_bulk_actions_params();
837 return;
838 }
839
840 let siteNames = {};
841
842 for (let id of allWebsiteIds) {
843 dashboard_update_site_status(id, '<i class="clock outline icon"></i>');
844 siteNames[id] = jQuery('.sync-site-status[siteid="' + id + '"]').attr('niceurl');
845 }
846 let initData = {
847 progressMax: nrOfWebsites,
848 title: 'Check abandoned ' + ('plugin' == which ? 'plugins' : 'themes'),
849 statusText: MainWP.I18n.t('started'),
850 callback: function () {
851 mainwpVars.bulkManageSitesTaskRunning = false;
852 mainwp_forceReload();
853 }
854 };
855 mainwpPopup('#mainwp-sync-sites-modal').init(initData);
856
857 mainwp_managesites_check_abandoned_all_int(allWebsiteIds, which);
858 };
859
860 let mainwp_managesites_check_abandoned_all_int = function (websiteIds, which) {
861 mainwpVars.websitesToUpgrade = websiteIds;
862 mainwpVars.currentWebsite = 0;
863 mainwpVars.websitesDone = 0;
864 mainwpVars.websitesTotal = mainwpVars.websitesToUpgrade.length;
865 mainwpVars.websitesLeft = mainwpVars.websitesToUpgrade.length;
866
867 mainwpVars.bulkTaskRunning = true;
868 mainwp_managesites_check_abandoned_all_loop_next(which);
869 };
870
871 let mainwp_managesites_check_abandoned_all_loop_next = function (which) {
872 while (mainwpVars.bulkTaskRunning && (mainwpVars.currentThreads < mainwpVars.maxThreads) && (mainwpVars.websitesLeft > 0)) {
873 mainwp_managesites_check_abandoned_all_upgrade_next(which);
874 }
875 };
876 let mainwp_managesites_check_abandoned_all_upgrade_next = function (which) {
877 mainwpVars.currentThreads++;
878 mainwpVars.websitesLeft--;
879
880 let websiteId = mainwpVars.websitesToUpgrade[mainwpVars.currentWebsite++];
881 dashboard_update_site_status(websiteId, '<i class="sync alternate loading icon"></i>');
882
883 mainwp_managesites_check_abandoned_int(websiteId, which);
884 };
885
886 let mainwp_managesites_check_abandoned_int = function (siteid, which) {
887
888 let data = mainwp_secure_data({
889 action: 'mainwp_check_abandoned',
890 siteId: siteid,
891 which: which
892 });
893
894 jQuery.ajax({
895 type: 'POST',
896 url: ajaxurl,
897 data: data,
898 success: function (pSiteid) {
899 return function (response) {
900 mainwpVars.currentThreads--;
901 mainwpVars.websitesDone++;
902 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(mainwpVars.websitesDone);
903 if (response.error != undefined) {
904 dashboard_update_site_status(pSiteid, '<i class="red times icon"></i>');
905 } else if (response.result && response.result == 'success') {
906 dashboard_update_site_status(pSiteid, '<i class="green check icon"></i>', true);
907 } else {
908 dashboard_update_site_status(pSiteid, '<i class="red times icon"></i>');
909 }
910 mainwp_managesites_check_abandoned_all_loop_next(which);
911 }
912 }(siteid),
913 dataType: 'json'
914 });
915 };
916
917 /**
918 * MainWP UI.
919 */
920 jQuery(function () {
921 jQuery('#reset-overview-settings').on('click', function () {
922 mainwp_confirm(MainWP.I18n.t('Are you sure?'), function () {
923 let which_set = jQuery('input[name=reset_overview_which_settings]').val();
924 if ('sidebar_settings' == which_set) {
925 jQuery('#mainwp_sidebarPosition').dropdown('set selected', 1);
926 } else if ('overview_settings' == which_set) {
927 jQuery('input[name=hide_update_everything]').prop('checked', false);
928 jQuery('.mainwp_hide_wpmenu_checkboxes input[name="mainwp_show_widgets[]"]').prop('checked', true);
929 }
930 if (jQuery('input[name=mainwp_manageposts_show_columns_settings]').length > 0 || jQuery('input[name=mainwp_managepages_show_columns_settings]').length > 0 || jQuery('input[name=mainwp_manageusers_show_columns_settings]').length > 0) {
931 jQuery('input[name="mainwp_show_columns[]"]').prop('checked', true);
932 }
933 jQuery('input[name=reset_overview_settings]').attr('value', 1);
934 jQuery('#submit-overview-settings').click();
935 }, false, false, true);
936 return false;
937 });
938 });
939
940 /**
941 * Sync Sites
942 */
943
944 jQuery(function () {
945 jQuery('#mainwp-sync-sites').on('click', function () {
946 mainwp_sync_sites_data();
947 });
948
949 // to compatible with extensions
950 jQuery('#dashboard_refresh').on('click', function () {
951 mainwp_sync_sites_data();
952 });
953 jQuery('.mainwp-sync-this-site').on('click', function () {
954 let syncSiteIds = [];
955 syncSiteIds.push(jQuery(this).attr('site-id'));
956 mainwp_sync_sites_data(syncSiteIds);
957 });
958 });
959
960 globalThis.mainwp_sync_sites_data = function (syncSiteIds, pAction) {
961 let allWebsiteIds = [];
962 jQuery('.dashboard_wp_id[error-status=0]').map(function (indx, el) {
963 allWebsiteIds.push(jQuery(el).val());
964 });
965 let globalSync = true;
966 let selectedIds = [], excludeIds = [];
967 if (Array.isArray(syncSiteIds)) {
968 jQuery.grep(allWebsiteIds, function (el) {
969 if (jQuery.inArray(el, syncSiteIds) === -1) {
970 excludeIds.push(el);
971 } else {
972 selectedIds.push(el);
973 }
974 });
975 for (let id of excludeIds) {
976 dashboard_update_site_hide(id);
977 }
978 allWebsiteIds = selectedIds;
979 globalSync = false;
980 }
981
982 for (let id of allWebsiteIds) {
983 dashboard_update_site_status(id, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Pending') + '"><i class="clock outline icon"></i></span>');
984 }
985
986 let nrOfWebsites = allWebsiteIds.length;
987
988 mainwpPopup('#mainwp-sync-sites-modal').init({
989 title: (pAction == 'checknow' ? MainWP.I18n.t('Check Now') : MainWP.I18n.t('Data Synchronization')),
990 progressMax: nrOfWebsites,
991 statusText: (pAction == 'checknow' ? 'checked' : 'synced'),
992 callback: function () {
993 mainwpVars.bulkTaskRunning = false;
994 history.pushState("", document.title, globalThis.location.pathname + globalThis.location.search); // to fix issue for url with hash
995 mainwp_forceReload();
996 }
997 });
998
999 if (jQuery('#mainwp-sync-sites-modal').attr('current-wpid') > 0) {
1000 globalSync = false;
1001 }
1002
1003 dashboard_update(allWebsiteIds, globalSync, pAction);
1004
1005 if (pAction != 'checknow') {
1006 if (nrOfWebsites > 0) {
1007 let data = {
1008 action: 'mainwp_status_saving',
1009 status: 'last_sync_sites',
1010 isGlobalSync: globalSync ? 1 : 0
1011 };
1012 jQuery.post(ajaxurl, mainwp_secure_data(data), function () {
1013
1014 });
1015 }
1016 }
1017 };
1018
1019 mainwpVars.websitesToUpdate = [];
1020 mainwpVars.websitesTotal = 0;
1021 mainwpVars.websitesLeft = 0;
1022 mainwpVars.websitesDone = 0;
1023 mainwpVars.currentWebsite = 0;
1024 mainwpVars.bulkTaskRunning = false;
1025 mainwpVars.currentThreads = 0;
1026 mainwpVars.maxThreads = mainwpParams['maximumSyncRequests'] == undefined ? 8 : mainwpParams['maximumSyncRequests'];
1027 mainwpVars.maxUpdateThreads = mainwpParams['maximumInstallUpdateRequests'] == undefined ? 3 : mainwpParams['maximumInstallUpdateRequests'];
1028
1029 let globalSync = true;
1030
1031 globalThis.dashboard_update = function (websiteIds, isGlobalSync, pAction) {
1032 mainwpVars.websitesToUpdate = websiteIds;
1033 mainwpVars.currentWebsite = 0;
1034 mainwpVars.websitesDone = 0;
1035 mainwpVars.successCount = 0;
1036 mainwpVars.websitesTotal = mainwpVars.websitesLeft = mainwpVars.websitesToUpdate.length;
1037 globalSync = isGlobalSync;
1038
1039 mainwpVars.bulkTaskRunning = true;
1040
1041 if (mainwpVars.websitesTotal == 0) {
1042 dashboard_update_done(pAction);
1043 } else {
1044 dashboard_loop_next(pAction);
1045 }
1046 };
1047
1048 (function () {
1049 // Create global namespace
1050 const sync = globalThis.dashboardSync = globalThis.dashboardSync || {
1051 container: null,
1052 statusMap: new Map(),
1053 rowMap: new Map(),
1054
1055 data: new Map(),
1056 queue: [],
1057
1058 scheduled: false,
1059 initialized: false,
1060
1061 BATCH_SIZE: 50
1062 };
1063
1064 // -----------------------------
1065 // INIT CACHE
1066 // -----------------------------
1067 function init() {
1068 if (sync.initialized) return;
1069
1070 sync.container = document.getElementById('sync-sites-status');
1071 if (!sync.container) return;
1072
1073 const nodes = sync.container.querySelectorAll('.sync-site-status');
1074
1075 for (const el of nodes) {
1076 const siteId = el.getAttribute('siteid');
1077 sync.statusMap.set(siteId, el);
1078 sync.rowMap.set(siteId, el.closest('.item'));
1079 }
1080
1081 sync.initialized = true;
1082 }
1083
1084 // Ensure DOM ready
1085 if (document.readyState === 'loading') {
1086 document.addEventListener('DOMContentLoaded', init);
1087 } else {
1088 init();
1089 }
1090
1091 // -----------------------------
1092 // PUBLIC API
1093 // -----------------------------
1094 globalThis.dashboard_update_site_status = function (siteId, newStatus, isSuccess) {
1095 if (!sync.initialized) return;
1096
1097 sync.data.set(siteId, {
1098 status: newStatus,
1099 success: isSuccess
1100 });
1101
1102 sync.queue.push(siteId);
1103
1104 // �
1105 increment success count ONCE
1106 if (isSuccess) {
1107 mainwpVars.successCount = (mainwpVars.successCount || 0) + 1;
1108 }
1109
1110 if (!sync.scheduled) {
1111 sync.scheduled = true;
1112 requestAnimationFrame(processQueue);
1113 }
1114 };
1115
1116 globalThis.dashboard_update_site_hide = function (siteId) {
1117 const sync = globalThis.dashboardSync;
1118 if (!sync?.initialized) return;
1119
1120 const rowEl = sync.rowMap.get(siteId);
1121 if (!rowEl) return;
1122
1123 rowEl.style.display = 'none';
1124 };
1125
1126 // -----------------------------
1127 // PROCESS QUEUE (BATCHED)
1128 // -----------------------------
1129 function processQueue() {
1130 sync.scheduled = false;
1131
1132 let count = 0;
1133
1134 while (sync.queue.length && count < sync.BATCH_SIZE) {
1135 const siteId = sync.queue.shift();
1136 const data = sync.data.get(siteId);
1137
1138 const statusEl = sync.statusMap.get(siteId);
1139 const rowEl = sync.rowMap.get(siteId);
1140
1141 if (!statusEl || !rowEl) continue;
1142
1143 // Avoid DOM read → use dataset cache
1144 if (statusEl.dataset.last !== data.status) {
1145 statusEl.innerHTML = data.status;
1146 statusEl.dataset.last = data.status;
1147 }
1148
1149 // No DOM move → just class toggle
1150 if (data.success) {
1151 rowEl.classList.add('is-success');
1152 }
1153
1154 count++;
1155 }
1156
1157 // Continue next frame if still pending
1158 if (sync.queue.length) {
1159 requestAnimationFrame(processQueue);
1160 }
1161 }
1162 })();
1163
1164 globalThis.dashboard_update_site_status_legacy = function (siteId, newStatus, isSuccess) {
1165 jQuery('.sync-site-status[siteid="' + siteId + '"]').html(newStatus);
1166 // Move successfully synced site to the bottom of the sync list
1167 if (isSuccess !== undefined && isSuccess) {
1168 let row = jQuery('.sync-site-status[siteid="' + siteId + '"]').closest('.item');
1169 jQuery(row).insertAfter(jQuery("#sync-sites-status .item").not('.disconnected-site').last());
1170 }
1171 };
1172
1173 globalThis.dashboard_update_site_hide_legacy = function (siteId) {
1174 jQuery('.sync-site-status[siteid="' + siteId + '"]').closest('.item').hide();
1175 };
1176
1177 let dashboard_loop_next = function (pAction) {
1178 while (mainwpVars.bulkTaskRunning && (mainwpVars.currentThreads < mainwpVars.maxThreads) && (mainwpVars.websitesLeft > 0)) {
1179 dashboard_update_next(pAction);
1180 }
1181 };
1182
1183 let dashboard_update_done = function (pAction) {
1184 mainwpVars.currentThreads--;
1185
1186 if (!mainwpVars.bulkTaskRunning) return;
1187
1188 mainwpVars.websitesDone++;
1189 if (mainwpVars.websitesDone > mainwpVars.websitesTotal) {
1190 mainwpVars.websitesDone = mainwpVars.websitesTotal;
1191 }
1192
1193 // �
1194 Cache popup instance (avoid re-query)
1195 const popup = mainwpVars._popup || (
1196 mainwpVars._popup = mainwpPopup('#mainwp-sync-sites-modal')
1197 );
1198
1199 popup.setProgressSite(mainwpVars.websitesDone);
1200
1201 // �
1202 Avoid DOM query for success count → track in JS
1203 if (mainwpVars.websitesDone === mainwpVars.websitesTotal) {
1204
1205 const successSites = mainwpVars.successCount || 0;
1206
1207 mainwpVars.bulkTaskRunning = false;
1208
1209 if (mainwpVars.websitesDone === successSites) {
1210 setTimeout(() => popup.close(true), 3000);
1211 }
1212
1213 return;
1214 }
1215
1216 dashboard_loop_next(pAction);
1217 };
1218
1219 let dashboard_update_done_legacy = function (pAction) {
1220 mainwpVars.currentThreads--;
1221 if (!mainwpVars.bulkTaskRunning)
1222 return;
1223 mainwpVars.websitesDone++;
1224 if (mainwpVars.websitesDone > mainwpVars.websitesTotal)
1225 mainwpVars.websitesDone = mainwpVars.websitesTotal;
1226
1227 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(mainwpVars.websitesDone);
1228
1229 if (mainwpVars.websitesDone == mainwpVars.websitesTotal) {
1230 let successSites = jQuery('#mainwp-sync-sites-modal .check.green.icon').length;
1231 if (mainwpVars.websitesDone == successSites) {
1232 mainwpVars.bulkTaskRunning = false;
1233 setTimeout(function () {
1234 mainwpPopup('#mainwp-sync-sites-modal').close(true);
1235 }, 3000);
1236 } else {
1237 mainwpVars.bulkTaskRunning = false;
1238 }
1239 return;
1240 }
1241
1242 dashboard_loop_next(pAction);
1243 };
1244
1245 let dashboard_update_next = function (pAction) {
1246 mainwpVars.currentThreads++;
1247 mainwpVars.websitesLeft--;
1248 let websiteId = mainwpVars.websitesToUpdate[mainwpVars.currentWebsite++];
1249 if ('checknow' == pAction) {
1250 dashboard_update_site_status(websiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Checking uptime status...') + '"><i class="sync alternate loading icon"></i></span>');
1251 } else {
1252 dashboard_update_site_status(websiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Syncing data...') + '"><i class="sync alternate loading icon"></i></span>');
1253 }
1254
1255 let data = mainwp_secure_data({
1256 action: ('checknow' == pAction ? 'mainwp_checksites' : 'mainwp_syncsites'),
1257 wp_id: websiteId,
1258 isGlobalSync: globalSync,
1259 bulkSync: mainwpVars.websitesTotal > 1 ? 1 : 0
1260 });
1261
1262
1263
1264 dashboard_update_next_int(websiteId, data, 0, pAction);
1265 };
1266
1267 let dashboard_update_next_int = function (websiteId, data, errors, action) {
1268 jQuery.ajax({
1269 type: 'POST',
1270 url: ajaxurl,
1271 data: data,
1272 success: function (pWebsiteId, pAction) {
1273 return function (response) {
1274 if (response.error) {
1275 let extErr = response.error;
1276 dashboard_update_site_status(pWebsiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + extErr + '"><i class="exclamation red icon"></i></span>');
1277 } else {
1278 dashboard_update_site_status(websiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Synchronization process completed successfully.') + '"><i class="check green icon"></i></span>', true);
1279 }
1280 dashboard_update_done(pAction);
1281 }
1282 }(websiteId, action),
1283 error: function (pWebsiteId, pData, pErrors, pAction) {
1284 return function () {
1285 if (pErrors > 5) {
1286 dashboard_update_site_status(pWebsiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process timed out. Please try again.') + '"><i class="exclamation yellow icon"></i></span>');
1287 dashboard_update_done(pAction);
1288 } else {
1289 pErrors++;
1290 dashboard_update_next_int(pWebsiteId, pData, pErrors, pAction);
1291 }
1292 }
1293 }(websiteId, data, errors, action),
1294 dataType: 'json'
1295 });
1296 };
1297
1298
1299 /**
1300 * Delete site changes actions.
1301 */
1302
1303 let mainwp_delete_nonmainwp_data_start = function () {
1304 mainwp_delete_nonmainwp_data_start_next();
1305 }
1306
1307 let mainwp_delete_nonmainwp_data_start_next = function () {
1308 while ((checkedBox = jQuery('#mainwp-module-log-records-body-table .check-column INPUT:checkbox:checked:first')) && (checkedBox.length > 0) && (bulkManageClientsCurrentThreads < bulkManageClientsMaxThreads)) { // NOSONAR -- modified out side the function.
1309 mainwp_delete_nonmainwp_data_next();
1310 }
1311 }
1312
1313 let mainwp_delete_nonmainwp_data_next = function () {
1314 mainwpVars.currentThreads++;
1315 mainwpVars.websitesLeft--;
1316 let websiteId = mainwpVars.websitesToUpdate[mainwpVars.currentWebsite++];
1317 dashboard_update_site_status(websiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Deleting...') + '"><i class="sync alternate loading icon"></i></span>');
1318 let data = mainwp_secure_data({
1319 action: 'mainwp_delete_non_mainwp_actions',
1320 wp_id: websiteId,
1321 });
1322 mainwp_delete_nonmainwp_data_next_int(websiteId, data, 0);
1323 };
1324
1325 let mainwp_delete_nonmainwp_data_next_int = function (websiteId, data, errors) {
1326 jQuery.ajax({
1327 type: 'POST',
1328 url: ajaxurl,
1329 data: data,
1330 success: function (pWebsiteId) {
1331 return function (response) {
1332 if (response.error) {
1333 let extErr = response.error;
1334 dashboard_update_site_status(pWebsiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + extErr + '"><i class="exclamation red icon"></i></span>');
1335 } else {
1336 dashboard_update_site_status(websiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process completed successfully.') + '"><i class="check green icon"></i></span>', true);
1337 }
1338 mainwp_delete_nonmainwp_data_done();
1339 }
1340 }(websiteId),
1341 error: function (pWebsiteId, pData, pErrors) {
1342 return function () {
1343 if (pErrors > 5) {
1344 dashboard_update_site_status(pWebsiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process timed out. Please try again.') + '"><i class="exclamation yellow icon"></i></span>');
1345 mainwp_delete_nonmainwp_data_done();
1346 } else {
1347 pErrors++;
1348 mainwp_delete_nonmainwp_data_next_int(pWebsiteId, pData, pErrors);
1349 }
1350 }
1351 }(websiteId, data, errors),
1352 dataType: 'json'
1353 });
1354 };
1355
1356
1357 let mainwp_delete_nonmainwp_data_done = function () {
1358 mainwpVars.currentThreads--;
1359 if (!mainwpVars.bulkTaskRunning)
1360 return;
1361 mainwpVars.websitesDone++;
1362 if (mainwpVars.websitesDone > mainwpVars.websitesTotal)
1363 mainwpVars.websitesDone = mainwpVars.websitesTotal;
1364
1365 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(mainwpVars.websitesDone);
1366
1367 if (mainwpVars.websitesDone == mainwpVars.websitesTotal) {
1368 jQuery("#mainwp-non-mainwp-changes-table tbody").fadeOut("slow");
1369 let successSites = jQuery('#mainwp-sync-sites-modal .check.green.icon').length;
1370 if (mainwpVars.websitesDone == successSites) {
1371 mainwpVars.bulkTaskRunning = false;
1372 setTimeout(function () {
1373 mainwpPopup('#mainwp-sync-sites-modal').close(true);
1374 }, 3000);
1375 } else {
1376 mainwpVars.bulkTaskRunning = false;
1377 }
1378 return;
1379 }
1380 mainwp_delete_nonmainwp_data_loop_next();
1381 };
1382
1383
1384 let mainwp_tool_disconnect_sites = function () {
1385
1386 mainwp_confirm('Are you sure that you want to disconnect your sites? This will function will break the connection and leave the MainWP Child plugin active and which makes your sites vulnerable.', function () {
1387 let allWebsiteIds = jQuery('.dashboard_wp_id[error-status=0]').map(function (indx, el) {
1388 return jQuery(el).val();
1389 });
1390
1391 for (let id of allWebsiteIds) {
1392 dashboard_update_site_status(id, '<i class="clock outline icon"></i>');
1393 }
1394
1395 let nrOfWebsites = allWebsiteIds.length;
1396
1397 mainwpPopup('#mainwp-sync-sites-modal').init({
1398 title: MainWP.I18n.t('Disconnect All Sites'),
1399 progressMax: nrOfWebsites,
1400 statusText: MainWP.I18n.t('disconnected'),
1401 callback: function () {
1402 mainwp_forceReload();
1403 }
1404 });
1405
1406 mainwpVars.websitesToUpdate = allWebsiteIds;
1407 mainwpVars.currentWebsite = 0;
1408 mainwpVars.websitesDone = 0;
1409 mainwpVars.websitesTotal = mainwpVars.websitesLeft = mainwpVars.websitesToUpdate.length;
1410
1411 mainwpVars.bulkTaskRunning = true;
1412
1413 if (mainwpVars.websitesTotal == 0) {
1414 mainwp_tool_disconnect_sites_done();
1415 } else {
1416 mainwp_tool_disconnect_sites_loop_next();
1417 }
1418 }, false, false, false, 'DISCONNECT');
1419 };
1420
1421 let mainwp_tool_disconnect_sites_done = function () {
1422 mainwpVars.currentThreads--;
1423 if (!mainwpVars.bulkTaskRunning)
1424 return;
1425 mainwpVars.websitesDone++;
1426 if (mainwpVars.websitesDone > mainwpVars.websitesTotal)
1427 mainwpVars.websitesDone = mainwpVars.websitesTotal;
1428
1429 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(mainwpVars.websitesDone);
1430
1431 mainwp_tool_disconnect_sites_loop_next();
1432 };
1433
1434 let mainwp_tool_disconnect_sites_loop_next = function () {
1435 while (mainwpVars.bulkTaskRunning && (mainwpVars.currentThreads < mainwpVars.maxThreads) && (mainwpVars.websitesLeft > 0)) { // NOSONAR - vars modified outside function.
1436 mainwp_tool_disconnect_sites_next();
1437 }
1438 };
1439
1440 let mainwp_tool_disconnect_sites_next = function () {
1441 mainwpVars.currentThreads++;
1442 mainwpVars.websitesLeft--;
1443 let websiteId = mainwpVars.websitesToUpdate[mainwpVars.currentWebsite++];
1444 dashboard_update_site_status(websiteId, '<i class="sync alternate loading icon"></i>');
1445 let data = mainwp_secure_data({
1446 action: 'mainwp_disconnect_site',
1447 wp_id: websiteId
1448 });
1449 mainwp_tool_disconnect_sites_next_int(websiteId, data, 0);
1450 };
1451
1452 let mainwp_tool_disconnect_sites_next_int = function (websiteId, data, errors) {
1453 jQuery.ajax({
1454 type: 'POST',
1455 url: ajaxurl,
1456 data: data,
1457 success: function (pWebsiteId) {
1458 return function (response) {
1459 if (response?.error) {
1460 dashboard_update_site_status(pWebsiteId, response.error + '<i class="exclamation red icon"></i>');
1461 } else if (response?.result == 'success') {
1462 dashboard_update_site_status(websiteId, '<i class="check green icon"></i>', true);
1463 } else {
1464 dashboard_update_site_status(pWebsiteId, MainWP.I18n.t('Undefined error!') + ' <i class="exclamation red icon"></i>');
1465 }
1466 mainwp_tool_disconnect_sites_done();
1467 }
1468 }(websiteId),
1469 error: function (pWebsiteId, pData, pErrors) {
1470 return function () {
1471 if (pErrors > 5) {
1472 dashboard_update_site_status(pWebsiteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process timed out. Please try again.') + '"><i class="exclamation yellow icon"></i></span>');
1473 mainwp_tool_disconnect_sites_done();
1474 } else {
1475 pErrors++;
1476 mainwp_tool_disconnect_sites_next_int(pWebsiteId, pData, pErrors);
1477 }
1478 }
1479 }(websiteId, data, errors),
1480 dataType: 'json'
1481 });
1482 };
1483
1484 let mainwp_tool_confirm_to_process = function (pObj) {
1485 let loc = jQuery(pObj).attr('href');
1486 mainwp_confirm('Are you sure?', function () {
1487 globalThis.location = loc;
1488 });
1489 };
1490
1491
1492 /**
1493 * Manage sites page
1494 */
1495
1496 jQuery(function ($) {
1497 jQuery('#mainwp-backup-type').on('change', function () {
1498 if (jQuery(this).val() == 'full')
1499 jQuery('.mainwp-backup-full-exclude').show();
1500 else
1501 jQuery('.mainwp-backup-full-exclude').hide();
1502 });
1503 jQuery('.mainwp-checkbox-showhide-elements').on('click', function () {
1504 let hiel = $(this).attr('hide-parent');
1505 if (hiel !== undefined && hiel !== '') {
1506 // support multi hide values.
1507 hiel.split(';').forEach((hi) => {
1508 mainwp_showhide_elements(hi, $(this).find('input').is(':checked'));
1509 });
1510 }
1511 let hideEvent = $(this).attr('fire-event-parent') ?? '';
1512 if (hideEvent != '') {
1513 // to sure click events finished.
1514 setTimeout(function () {
1515 document.dispatchEvent(new Event(hideEvent));
1516 }, 200);
1517 }
1518 });
1519
1520 jQuery('.mainwp-selecter-showhide-elements').on('change', function () {
1521 let hiel = $(this).attr('hide-parent');
1522 let hival = $(this).attr('hide-value');
1523 hival = hival.split(';'); // support multi hide values.
1524 let selectedval = $(this).val();
1525 mainwp_showhide_elements(hiel, hival.includes(selectedval));
1526 });
1527 });
1528
1529 function mainwp_showhide_elements(attEl, valHi) {
1530 // support multi attr to hide.
1531 if (valHi) {
1532 attEl.split(';').forEach(function (att) {
1533 jQuery('[hide-element=' + att.trim() + ']').fadeOut(300);
1534 jQuery('[hide-sub-element=' + att.trim() + ']').fadeOut(300);
1535 });
1536 } else {
1537 attEl.split(';').forEach(function (att) {
1538 jQuery('[hide-element=' + att.trim() + ']').fadeIn(300);
1539 jQuery('[hide-sub-element=' + att.trim() + ']').fadeIn(300);
1540 });
1541 }
1542 }
1543
1544
1545 jQuery(function ($) {
1546 $('#mainwp_settings_verify_connection_method').on('change', function () {
1547 let selectedval = $(this).val();
1548 if (selectedval == 2) { // phpseclib.
1549 $('.mainwp-hide-elemenent-sign-algo').fadeOut(200);
1550 } else {
1551 $('.mainwp-hide-elemenent-sign-algo').fadeIn(200);
1552 }
1553 });
1554
1555 $('#mainwp_managesites_edit_verify_connection_method').on('change', function () {
1556 let selectedval = $(this).val();
1557 if (selectedval == 2 || selectedval == 3) { // phpseclib.
1558 $('.mainwp-hide-elemenent-sign-algo').fadeOut(200);
1559 } else {
1560 $('.mainwp-hide-elemenent-sign-algo').fadeIn(200);
1561 }
1562 });
1563
1564
1565 $('#mainwp_managesites_edit_openssl_alg').on('change', function () {
1566 let selectedval = $(this).val();
1567 if (selectedval == 1) {
1568 $('.mainwp-hide-elemenent-sign-algo-note').fadeIn(200);
1569 } else {
1570 $('.mainwp-hide-elemenent-sign-algo-note').fadeOut(200);
1571 }
1572 });
1573
1574 $('#mainwp_settings_openssl_alg').on('change', function () {
1575 let selectedval = $(this).val();
1576 if (selectedval == 1) {
1577 $('.mainwp-hide-elemenent-sign-algo-note').fadeIn(200);
1578 } else {
1579 $('.mainwp-hide-elemenent-sign-algo-note').fadeOut(200);
1580 }
1581 });
1582
1583 })
1584
1585 jQuery(function () {
1586 jQuery(document).on('change', '#mainwp_managesites_add_wpurl', function () {
1587 let url = jQuery('#mainwp_managesites_add_wpurl').val().trim();
1588 let protocol = jQuery('#mainwp_managesites_add_wpurl_protocol').val();
1589
1590 if (url.lastIndexOf('http://') === 0) {
1591 protocol = 'http';
1592 url = url.substring(7);
1593 } else if (url.lastIndexOf('https://') === 0) {
1594 protocol = 'https';
1595 url = url.substring(8);
1596 }
1597
1598 if (jQuery('#mainwp_managesites_add_wpname').val() == '') {
1599 jQuery('#mainwp_managesites_add_wpname').val(url);
1600 }
1601 jQuery('#mainwp_managesites_add_wpurl').val(url);
1602 jQuery('#mainwp_managesites_add_wpurl_protocol').val(protocol).trigger("change");
1603 });
1604
1605 // Trigger the single site reconnect process
1606 jQuery('.mainwp-manage-wpsites-table').on('click', '.mainwp_site_reconnect', function () {
1607 mainwp_managesites_reconnect(jQuery(this));
1608 return false;
1609 });
1610
1611 jQuery('#mainwp-sites-previews').on('click', '.mainwp_site_card_reconnect', function () {
1612 mainwp_managesites_cards_reconnect(jQuery(this));
1613 return false;
1614 });
1615
1616 jQuery(document).on('click', '.mainwp-updates-overview-reconnect-site', function () {
1617 mainwp_site_overview_reconnect(jQuery(this));
1618 return false;
1619 });
1620
1621 jQuery(".chk-sync-install-plugin").on('change', function () {
1622 let parent = jQuery(this).closest('.sync-ext-row');
1623 let opts = parent.find(".sync-options input[type='checkbox']");
1624 if (jQuery(this).is(':checked')) {
1625 opts.prop("checked", true);
1626 } else {
1627 opts.prop("checked", false);
1628 ///opts.attr( "disabled", "disabled" );
1629 }
1630 });
1631
1632 managesites_init();
1633 });
1634
1635 jQuery(document).on('change', '#mainwp_managesites_verify_installed_child', function () {
1636 if (jQuery(this).is(':checked')) {
1637 jQuery('#mainwp_message_verify_installed_child').hide();
1638 }
1639 });
1640
1641 globalThis.managesites_init = function () {
1642 mainwp_set_message_zone('#mainwp-message-zone');
1643 jQuery('.sync-ext-row span.status').html('');
1644 jQuery('.sync-ext-row span.status').css('color', '#0073aa');
1645 };
1646
1647 let mainwp_site_overview_reconnect = function (pElement) {
1648 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + 'Trying to reconnect. Please wait...', '');
1649 let data = mainwp_secure_data({
1650 action: 'mainwp_reconnectwp',
1651 siteid: pElement.attr('siteid')
1652 });
1653
1654 jQuery.post(ajaxurl, data, function () {
1655 return function (response) {
1656 response = response.trim();
1657 if (response.substring(0, 5) == 'ERROR') {
1658 let error;
1659 if (response.length == 5) {
1660 error = 'Undefined error! Please try again. If the process keeps failing, please review <a href="https://docs.mainwp.com/">MainWP Knowledgebase</a>, and if you still have issues, please let us know in the <a href="https://community.mainwp.com/c/community-support/5">MainWP Community</a>.'; // NOSONAR - noopener - open safe.
1661 feedback('mainwp-message-zone', error, 'red');
1662 } else {
1663 error = response.substring(6);
1664 let err = mainwp_js_get_error_not_detected_connect(error, 'html_msg', 'mainwp-message-zone');
1665 if (false === err) {
1666 feedback('mainwp-message-zone', error, 'red'); // it is not json error string.
1667 }
1668 }
1669 } else if ('reconnect_failed' === response) {
1670 mainwp_set_message_zone('#mainwp-message-zone');
1671
1672 jQuery('#mainwp-reconnect-site-with-user-passwd-modal').modal({
1673 onHide: function () {
1674 mainwp_forceReload();
1675 },
1676 closable: false
1677 }).modal('show');
1678 jQuery('#mainwp_managesites_add_wpadmin').val(pElement.attr('adminuser'));
1679 jQuery(document).on('click', '#mainwp-popup-reconnect-site-btn', function () {
1680 mainwp_reconnect_with_pw(pElement.attr('siteid'));
1681 return false;
1682 });
1683 } else {
1684 mainwp_set_message_zone('#mainwp-message-zone');
1685 mainwp_forceReload();
1686 }
1687 }
1688 }());
1689 };
1690
1691 let mainwp_reconnect_with_pw = function (siteid) {
1692 mainwp_set_message_zone('#mainwp-message-zone-reconnect');
1693 let errors = [];
1694 if (jQuery('#mainwp_managesites_add_wpadmin').val().trim() == '') {
1695 errors.push('Please enter a username of the website administrator.');
1696 }
1697
1698 if (jQuery('#mainwp_managesites_add_admin_pwd').val().trim() == '') {
1699 errors.push('Please enter password of the website administrator.');
1700 }
1701
1702 if (errors.length > 0) {
1703 mainwp_set_message_zone('#mainwp-message-zone-reconnect', errors.join('</br>'), 'red');
1704 return;
1705 }
1706
1707 mainwp_set_message_zone('#mainwp-message-zone-reconnect', '<i class="notched circle loading icon"></i> ' + 'Trying to reconnect. Please wait...', 'green');
1708 let data = mainwp_secure_data({
1709 action: 'mainwp_reconnectwp',
1710 managesites_add_wpadmin: jQuery('#mainwp_managesites_add_wpadmin').val(),
1711 managesites_add_adminpwd: encodeURIComponent(jQuery('#mainwp_managesites_add_admin_pwd').val()),
1712 siteid: siteid
1713 });
1714
1715 jQuery.post(ajaxurl, data, function (response) {
1716 response = response.trim();
1717 mainwp_set_message_zone('#mainwp-message-zone-reconnect');
1718 if (response.substring(0, 5) == 'ERROR') {
1719 let error;
1720 if (response.length == 5) {
1721 error = 'Undefined error! Please try again. If the process keeps failing, please review this <a href="https://docs.mainwp.com/troubleshooting/potential-issues">Knowledgebase document</a>, and if you still have issues, please let us know in the <a href="https://community.mainwp.com/c/community-support/5">MainWP Community</a>.'; // NOSONAR - noopener - open safe.
1722 mainwp_set_message_zone('#mainwp-message-zone-reconnect', error, 'red');
1723 } else {
1724 error = response.substring(6);
1725 let err = mainwp_js_get_error_not_detected_connect(error, 'html_msg', 'mainwp-message-zone-reconnect');
1726 if (false === err) {
1727 mainwp_set_message_zone('#mainwp-message-zone-reconnect', error, 'red'); // it is not json error string.
1728 }
1729 }
1730 } else if ('reconnect_failed' === response) {
1731 // do not show reconnect popup again.
1732 mainwp_set_message_zone('#mainwp-message-zone-reconnect', mainwp_get_reconnect_error(response, siteid), 'red');
1733 } else {
1734 mainwp_set_message_zone('#mainwp-message-zone-reconnect', response, 'green');
1735 mainwp_forceReload();
1736 }
1737 });
1738 };
1739
1740
1741 let mainwp_managesites_reconnect = function (pElement) {
1742 let wrapElement = pElement.closest('tr');
1743 wrapElement.html('<td colspan="999"><i class="notched circle loading icon"></i> ' + 'Trying to reconnect. Please wait...' + '</td>');
1744 let siteid = wrapElement.attr('siteid');
1745 let data = mainwp_secure_data({
1746 action: 'mainwp_reconnectwp',
1747 siteid: siteid
1748 });
1749
1750 jQuery.post(ajaxurl, data, function (pWrapElement) {
1751 return function (response) {
1752 response = response.trim();
1753 pWrapElement.hide(); // hide reconnect item
1754 if (response.substring(0, 5) == 'ERROR') {
1755 let error;
1756 if (response.length == 5) {
1757 error = 'Undefined error! Please try again. If the process keeps failing, please review this <a href="https://docs.mainwp.com/troubleshooting/potential-issues">Knowledgebase document</a>, and if you still have issues, please let us know in the <a href="https://community.mainwp.com/c/community-support/5">MainWP Community</a>.'; // NOSONAR - noopener - open safe.
1758 feedback('mainwp-message-zone', error, 'red');
1759 } else {
1760 error = response.substring(6);
1761 let err = mainwp_js_get_error_not_detected_connect(error, 'html_msg', 'mainwp-message-zone');
1762 if (false === err) {
1763 feedback('mainwp-message-zone', error, 'red'); // it is not json error string.
1764 }
1765 }
1766 } else if ('reconnect_failed' === response) {
1767 feedback('mainwp-message-zone', mainwp_get_reconnect_error(response, siteid), 'error');
1768 } else {
1769 feedback('mainwp-message-zone', response, 'green');
1770 }
1771 setTimeout(function () {
1772 mainwp_forceReload();
1773 }, 6000);
1774 }
1775
1776 }(wrapElement));
1777 };
1778
1779 let mainwp_managesites_cards_reconnect = function (element) {
1780 element.html('<i class="notched loading circle icon"></i> Reconnecting...');
1781 let siteid = element.attr('site-id');
1782 let data = mainwp_secure_data({
1783 action: 'mainwp_reconnectwp',
1784 siteid: siteid
1785 });
1786
1787 jQuery.post(ajaxurl, data, function (element) {
1788 return function (response) {
1789 response = response.trim();
1790 element.hide();
1791 if (response.substring(0, 5) == 'ERROR') {
1792 let error;
1793 if (response.length == 5) {
1794 error = 'Undefined error! Please try again. If the process keeps failing, please review this <a href="https://docs.mainwp.com/troubleshooting/potential-issues">Knowledgebase document</a>, and if you still have issues, please let us know in the <a href="https://community.mainwp.com/c/community-support/5">MainWP Community</a>.'; // NOSONAR - noopener - open safe.
1795 feedback('mainwp-message-zone', error, 'red');
1796 } else {
1797 error = response.substring(6);
1798 let err = mainwp_js_get_error_not_detected_connect(error, 'html_msg', 'mainwp-message-zone');
1799 if (false === err) {
1800 feedback('mainwp-message-zone', error, 'red'); // it is not json error string.
1801 }
1802 }
1803 } else if ('reconnect_failed' === response) {
1804 feedback('mainwp-message-zone', mainwp_get_reconnect_error(response, siteid), 'error');
1805 } else {
1806 feedback('mainwp-message-zone', response, 'green');
1807 }
1808 setTimeout(function () {
1809 mainwp_forceReload();
1810 }, 6000);
1811 }
1812
1813 }(element));
1814 };
1815
1816 // Connect a new website
1817 let mainwp_managesites_add = function () {
1818
1819 managesites_init();
1820
1821 let valid_input = mainwp_managesites_add_valid();
1822
1823 if (!valid_input) {
1824 return;
1825 }
1826
1827 feedback('mainwp-message-zone', MainWP.I18n.t('Adding the site to your MainWP Dashboard. Please wait...'), 'green');
1828
1829 jQuery('#mainwp_managesites_add').attr('disabled', 'true'); //disable button to add..
1830
1831 //Check if valid user & rulewp is installed?
1832 let url = jQuery('#mainwp_managesites_add_wpurl_protocol').val() + '://' + jQuery('#mainwp_managesites_add_wpurl').val().trim();
1833
1834 if (!url.endsWith('/')) {
1835 url += '/';
1836 }
1837
1838 let name = jQuery('#mainwp_managesites_add_wpname').val().trim();
1839 name = name.replaceAll('"', '&quot;');
1840
1841 let data = mainwp_secure_data({
1842 action: 'mainwp_checkwp',
1843 name: name,
1844 url: url,
1845 admin: jQuery('#mainwp_managesites_add_wpadmin').val().trim(),
1846 verify_certificate: jQuery('#mainwp_managesites_verify_certificate').is(':checked') ? 1 : 0,
1847 ssl_version: jQuery('#mainwp_managesites_add_ssl_version').val(),
1848 http_user: jQuery('#mainwp_managesites_add_http_user').val().trim(),
1849 http_pass: jQuery('#mainwp_managesites_add_http_pass').val().trim()
1850 });
1851
1852 jQuery.post(ajaxurl, data, function (res_things) { // NOSONAR - function complexity.
1853 let response = res_things.response;
1854 response = response.trim();
1855 let errors = [];
1856 let url = jQuery('#mainwp_managesites_add_wpurl_protocol').val() + '://' + jQuery('#mainwp_managesites_add_wpurl').val().trim();
1857 if (!url.endsWith('/')) {
1858 url += '/';
1859 }
1860
1861 url = url.replaceAll('"', '&quot;');
1862
1863 let show_resp = MainWP.I18n.t('Click %1here%2 to see response from the child site.', '<a href="javascript:void(0)" class="mainwp-show-response">', '</a>');
1864
1865 let resp_data = res_things.resp_data ? res_things.resp_data : '';
1866 if ('0' == resp_data) {
1867 resp_data = '';
1868 }
1869 jQuery('#mainwp-response-data-container').attr('resp-data', resp_data);
1870
1871 if (response == 'HTTPERROR') {
1872 errors.push(MainWP.I18n.t('This site can not be reached! Please use the Test Connection feature and see if the positive response will be returned. For additional help, please review this <a href="https://docs.mainwp.com/troubleshooting/potential-issues/">Knowledgebase document</a>, and if you still have issues, please let us know in the <a href="https://managers.mainwp.com/c/community-support/5">MainWP Community</a>.')); // NOSONAR - noopener - open safe.
1873 } else if (response == 'NOMAINWP') {
1874 errors.push(mainwp_js_get_error_not_detected_connect());
1875 } else if (response.substring(0, 5) == 'ERROR') {
1876 if (response.length == 5) {
1877 errors.push(MainWP.I18n.t('Undefined error occurred. Please try again. If the issue does not resolve, please review this <a href="https://docs.mainwp.com/troubleshooting/potential-issues/">Knowledgebase document</a>, and if you still have issues, please let us know in the <a href="https://managers.mainwp.com/c/community-support/5">MainWP Community</a>.')); // NOSONAR - noopener - open safe.
1878 } else {
1879 errors.push(MainWP.I18n.t('Error detected: ') + response.substring(6));
1880 }
1881 } else if (response == 'OK') {
1882 jQuery('#mainwp_managesites_add').attr('disabled', 'true'); //Disable add button
1883
1884 let name = jQuery('#mainwp_managesites_add_wpname').val();
1885 name = name.replaceAll('"', '&quot;');
1886 let group_ids = jQuery('#mainwp_managesites_add_addgroups').dropdown('get value');
1887 let client_id = jQuery('#mainwp_managesites_add_client_id').length ? jQuery('#mainwp_managesites_add_client_id').dropdown('get value') : 0;
1888 let data = mainwp_secure_data({
1889 action: 'mainwp_addwp',
1890 managesites_add_wpname: name,
1891 managesites_add_wpurl: url,
1892 managesites_add_wpadmin: jQuery('#mainwp_managesites_add_wpadmin').val(),
1893 managesites_add_adminpwd: encodeURIComponent(jQuery('#mainwp_managesites_add_admin_pwd').val().trim()),
1894 managesites_add_uniqueId: jQuery('#mainwp_managesites_add_uniqueId').val(),
1895 ssl_verify: jQuery('#mainwp_managesites_verify_certificate').is(':checked') ? 1 : 0,
1896 ssl_version: jQuery('#mainwp_managesites_add_ssl_version').val(),
1897 groupids: group_ids,
1898 clientid: client_id,
1899 selected_icon: jQuery('#mainwp_managesites_add_site_select_icon_hidden').val(),
1900 cust_color: jQuery('#mainwp_managesites_add_site_color').val(),
1901 uploaded_icon: jQuery('#mainwp_managesites_add_site_uploaded_icon_hidden').val(),
1902 managesites_add_http_user: jQuery('#mainwp_managesites_add_http_user').val(),
1903 managesites_add_http_pass: jQuery('#mainwp_managesites_add_http_pass').val(),
1904 });
1905
1906 // to support add client reports tokens values
1907 jQuery("input[name^='creport_token_']").each(function () {
1908 let tname = jQuery(this).attr('name');
1909 let tvalue = jQuery(this).val();
1910 data[tname] = tvalue;
1911 });
1912
1913 // support hooks fields
1914 jQuery(".mainwp_addition_fields_addsite input").each(function () {
1915 let tname = jQuery(this).attr('name');
1916 let tvalue = jQuery(this).val();
1917 data[tname] = tvalue;
1918 });
1919
1920 jQuery.post(ajaxurl, data, function (res_things) {
1921 let site_id = 0;
1922 if (res_things.error) {
1923 response = 'Error detected: ' + res_things.error;
1924 } else {
1925 response = res_things.response;
1926 site_id = res_things.siteid;
1927 }
1928 response = response.trim();
1929 managesites_init();
1930
1931 resp_data = res_things.resp_data ? res_things.resp_data : '';
1932 if ('0' == resp_data) {
1933 resp_data = '';
1934 }
1935 jQuery('#mainwp-response-data-container').attr('resp-data', resp_data);
1936
1937 if (response.substring(0, 5) == 'ERROR') {
1938 mainwp_set_message_zone('#mainwp-message-zone', '', '', true);
1939 feedback('mainwp-message-zone', response.substring(6) + (resp_data == '' ? '' : '<br>' + show_resp), 'red');
1940 } else {
1941 mainwp_set_message_zone('#mainwp-message-zone', '', '', true);
1942 feedback('mainwp-message-zone', response, 'green');
1943
1944 if (site_id > 0) {
1945 jQuery('.sync-ext-row').attr('status', 'queue');
1946 setTimeout(function () {
1947 mainwp_managesites_sync_extension_start_next(site_id);
1948 }, 1000);
1949 }
1950
1951 //Reset fields
1952 jQuery('#mainwp_managesites_add_wpname').val('');
1953 jQuery('#mainwp_managesites_add_wpurl').val('');
1954 jQuery('#mainwp_managesites_add_wpurl_protocol').val('https');
1955 jQuery('#mainwp_managesites_add_wpadmin').val('');
1956 jQuery('#mainwp_managesites_add_admin_pwd').val('');
1957 jQuery('#mainwp_managesites_add_uniqueId').val('');
1958 jQuery('#mainwp_managesites_add_addgroups').dropdown('clear');
1959 jQuery('#mainwp_managesites_verify_certificate').val(1);
1960
1961 jQuery("input[name^='creport_token_']").each(function () {
1962 jQuery(this).val('');
1963 });
1964
1965 // support hooks fields
1966 jQuery(".mainwp_addition_fields_addsite input").each(function () {
1967 jQuery(this).val('');
1968 });
1969 }
1970
1971 jQuery('#mainwp_managesites_add').prop("disabled", false); //Enable add button
1972 }, 'json');
1973 }
1974 if (errors.length > 0) {
1975 mainwp_set_message_zone('#mainwp-message-zone', '', '', true);
1976 managesites_init();
1977 jQuery('#mainwp_managesites_add').prop("disabled", false); //Enable add button
1978 if (resp_data != '') {
1979 errors.push(show_resp);
1980 }
1981 feedback('mainwp-message-zone', errors.join('<br />'), 'red');
1982 }
1983 }, 'json');
1984 };
1985
1986 let mainwp_managesites_add_valid = function () {
1987
1988 if (jQuery('#mainwp_managesites_verify_installed_child').is(':checked')) {
1989 jQuery('#mainwp_message_verify_installed_child').hide();
1990 } else {
1991 jQuery('#mainwp_message_verify_installed_child').show();
1992 scrollElementTop('mainwp_message_verify_installed_child');
1993 return false;
1994 }
1995
1996 let errors = [];
1997
1998 if (jQuery('#mainwp_managesites_add_wpname').val().trim() == '') {
1999 errors.push(MainWP.I18n.t('Please enter a name for the website.'));
2000 }
2001 if (jQuery('#mainwp_managesites_add_wpurl').val().trim() == '') {
2002 errors.push(MainWP.I18n.t('Please enter a valid URL for your site.'));
2003 } else {
2004 let url = jQuery('#mainwp_managesites_add_wpurl').val().trim();
2005 if (!url.endsWith('/')) {
2006 url += '/';
2007 }
2008
2009 jQuery('#mainwp_managesites_add_wpurl').val(url);
2010
2011 if (!isUrl(jQuery('#mainwp_managesites_add_wpurl_protocol').val() + '://' + jQuery('#mainwp_managesites_add_wpurl').val())) {
2012 errors.push(MainWP.I18n.t('Please enter a valid URL for your site.'));
2013 }
2014 }
2015 if (jQuery('#mainwp_managesites_add_wpadmin').val().trim() == '') {
2016 errors.push(MainWP.I18n.t('Please enter a username of the website administrator.'));
2017 }
2018
2019 if (errors.length > 0) {
2020 feedback('mainwp-message-zone', errors.join('<br />'), 'yellow');
2021 return false;
2022 }
2023 return true;
2024 }
2025
2026
2027 let mainwp_managesites_sync_extension_start_next = function (siteId) {
2028 let pluginToInstall = jQuery('.sync-ext-row[status="queue"]:first')
2029 while (pluginToInstall && (pluginToInstall.length > 0) && (bulkInstallCurrentThreads < 1)) { // NOSONAR - modified outside the function, bulkInstallMaxThreads - to fix install plugins and apply settings failed issue.
2030 pluginToInstall.attr('status', 'progress');
2031 mainwp_managesites_sync_extension_start_specific(pluginToInstall, siteId);
2032 pluginToInstall = jQuery('.sync-ext-row[status="queue"]:first');
2033 }
2034
2035 if ((pluginToInstall.length == 0) && (bulkInstallCurrentThreads == 0)) { // NOSONAR - modified outside the function.
2036 jQuery('#mwp_applying_ext_settings').remove();
2037 }
2038 };
2039
2040 let mainwp_managesites_sync_extension_start_specific = function (pPluginToInstall, pSiteId) {
2041 let syncGlobalSettings = pPluginToInstall.find(".sync-global-options input[type='checkbox']:checked").length > 0;
2042 let install_plugin = pPluginToInstall.find(".sync-install-plugin input[type='checkbox']:checked").length > 0;
2043 let apply_settings = pPluginToInstall.find(".sync-options input[type='checkbox']:checked").length > 0;
2044
2045 if (syncGlobalSettings) {
2046 mainwp_extension_apply_plugin_settings(pPluginToInstall, pSiteId, true);
2047 } else if (install_plugin) {
2048 mainwp_extension_prepareinstallplugin(pPluginToInstall, pSiteId);
2049 } else if (apply_settings) {
2050 mainwp_extension_apply_plugin_settings(pPluginToInstall, pSiteId, false);
2051 } else {
2052 mainwp_managesites_sync_extension_start_next(pSiteId);
2053 return;
2054 }
2055 };
2056
2057 let mainwp_extension_prepareinstallplugin = function (pPluginToInstall, pSiteId) {
2058 let site_Ids = [];
2059 site_Ids.push(pSiteId);
2060 bulkInstallCurrentThreads++;
2061 let plugin_slug = pPluginToInstall.find(".sync-install-plugin").attr('slug');
2062 let workingEl = pPluginToInstall.find(".sync-install-plugin i");
2063 let statusEl = pPluginToInstall.find(".sync-install-plugin span.status");
2064
2065 let data = {
2066 action: 'mainwp_ext_prepareinstallplugintheme',
2067 type: 'plugin',
2068 slug: plugin_slug,
2069 'selected_sites[]': site_Ids,
2070 selected_by: 'site',
2071 };
2072
2073 workingEl.show();
2074 statusEl.html(MainWP.I18n.t('Preparing for installation...'));
2075
2076 jQuery.post(ajaxurl, data, function (response) {
2077 workingEl.hide();
2078 if (response?.sites[pSiteId] === undefined) {
2079 statusEl.css('color', 'red');
2080 statusEl.html(MainWP.I18n.t('Error while preparing the installation. Please, try again.'));
2081 bulkInstallCurrentThreads--;
2082 } else {
2083 statusEl.html(MainWP.I18n.t('Installing...'));
2084 let data = mainwp_secure_data({
2085 action: 'mainwp_ext_performinstallplugintheme',
2086 type: 'plugin',
2087 url: response.url,
2088 siteId: pSiteId,
2089 activatePlugin: true,
2090 overwrite: false,
2091 });
2092 workingEl.show();
2093 jQuery.post(ajaxurl, data, function (response) {
2094 workingEl.hide();
2095 let apply_settings = false;
2096 let syc_msg = '';
2097 let _success = false;
2098 if ((response?.ok[pSiteId] != undefined)) {
2099 syc_msg = MainWP.I18n.t('Installation successful!');
2100 statusEl.html(syc_msg);
2101 apply_settings = pPluginToInstall.find(".sync-options input[type='checkbox']:checked").length > 0;
2102 if (apply_settings) {
2103 mainwp_extension_apply_plugin_settings(pPluginToInstall, pSiteId, false);
2104 }
2105 _success = true;
2106 } else if (response?.errors[pSiteId] === undefined) {
2107 syc_msg = MainWP.I18n.t('Installation failed!');
2108 statusEl.html(syc_msg);
2109 statusEl.css('color', 'red');
2110 } else {
2111 syc_msg = MainWP.I18n.t('Installation failed!') + ': ' + response.errors[pSiteId][1];
2112 statusEl.html(syc_msg);
2113 statusEl.css('color', 'red');
2114 }
2115
2116 if (syc_msg != '') {
2117 if (_success)
2118 syc_msg = '<span style="color:#0073aa">' + syc_msg + '!</span>';
2119 else
2120 syc_msg = '<span style="color:red">' + syc_msg + '!</span>';
2121 jQuery('#mainwp-message-zone').append('<br/>' + pPluginToInstall.find(".sync-install-plugin").attr('plugin_name') + ' ' + syc_msg);
2122 }
2123
2124 if (!apply_settings) {
2125 bulkInstallCurrentThreads--;
2126 mainwp_managesites_sync_extension_start_next(pSiteId);
2127 }
2128 }, 'json');
2129 }
2130 }, 'json');
2131 }
2132
2133 let mainwp_extension_apply_plugin_settings = function (pPluginToInstall, pSiteId, pGlobal) {
2134 let extSlug = pPluginToInstall.attr('slug');
2135 let workingEl = pPluginToInstall.find(".options-row i");
2136 let statusEl = pPluginToInstall.find(".options-row span.status");
2137 if (pGlobal)
2138 bulkInstallCurrentThreads++;
2139
2140 let data = mainwp_secure_data({
2141 action: 'mainwp_ext_applypluginsettings',
2142 ext_dir_slug: extSlug,
2143 siteId: pSiteId
2144 });
2145
2146 workingEl.show();
2147 statusEl.html(MainWP.I18n.t('Applying settings...'));
2148 jQuery.post(ajaxurl, data, function (response) { // NOSONAR - complex.
2149 workingEl.hide();
2150 let syc_msg = '';
2151 let _success = false;
2152 if (response) {
2153 if (response.result && response.result == 'success') {
2154 let msg = '';
2155 if (response.message != undefined) {
2156 msg = ' ' + response.message;
2157 }
2158 statusEl.html(MainWP.I18n.t('Applying settings successful!') + msg);
2159 syc_msg = MainWP.I18n.t('Successful');
2160 _success = true
2161 } else if (response.error === undefined) {
2162 statusEl.html(MainWP.I18n.t('Applying settings failed!'));
2163 statusEl.css('color', 'red');
2164 syc_msg = MainWP.I18n.t('failed');
2165 } else {
2166 statusEl.html(response.error);
2167 statusEl.css('color', 'red');
2168 syc_msg = response.error;
2169 }
2170 } else {
2171 statusEl.html(MainWP.I18n.t('Undefined error!'));
2172 statusEl.css('color', 'red');
2173 syc_msg = MainWP.I18n.t('failed');
2174 }
2175
2176 if (syc_msg != '') {
2177 if (_success)
2178 syc_msg = '<span style="color:#0073aa">' + syc_msg + '!</span>';
2179 else
2180 syc_msg = '<span style="color:red">' + syc_msg + '!</span>';
2181 if (pGlobal) {
2182 syc_msg = MainWP.I18n.t('Apply global %1 options', pPluginToInstall.attr('ext_name')) + ' ' + syc_msg;
2183 } else {
2184 syc_msg = MainWP.I18n.t('Apply %1 settings', pPluginToInstall.find('.sync-install-plugin').attr('plugin_name')) + ' ' + syc_msg;
2185 }
2186 jQuery('#mainwp-message-zone').append('<br/>' + syc_msg);
2187 }
2188 bulkInstallCurrentThreads--;
2189 mainwp_managesites_sync_extension_start_next(pSiteId);
2190 }, 'json');
2191 }
2192
2193 // Test Connection (Add Site Page)
2194 let mainwp_managesites_test = function () {
2195
2196 let errors = [];
2197
2198 if (jQuery('#mainwp_managesites_add_wpurl').val().trim() == '') {
2199 errors.push(MainWP.I18n.t('Please enter a valid URL for your site.'));
2200 } else {
2201 let clean_url = jQuery('#mainwp_managesites_add_wpurl').val().trim();
2202 let protocol = jQuery('#mainwp_managesites_add_wpurl_protocol').val();
2203 let url = protocol + '://' + clean_url;
2204 if (!url.endsWith('/')) {
2205 url += '/';
2206 }
2207
2208 if (!isUrl(url)) {
2209 errors.push(MainWP.I18n.t('Please enter a valid URL for your site'));
2210 }
2211 }
2212
2213 if (errors.length > 0) {
2214 feedback('mainwp-message-zone', errors.join('<br />'), 'red');
2215 } else {
2216 jQuery('#mainwp-test-connection-modal').modal('setting', 'closable', false).modal('show');
2217 jQuery('#mainwp-test-connection-modal .dimmer').show();
2218 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').hide();
2219
2220 let clean_url = jQuery('#mainwp_managesites_add_wpurl').val().trim();
2221 let protocol = jQuery('#mainwp_managesites_add_wpurl_protocol').val();
2222 let url = protocol + '://' + clean_url;
2223
2224 if (!url.endsWith('/')) {
2225 url += '/';
2226 }
2227
2228 let data = mainwp_secure_data({
2229 action: 'mainwp_testwp',
2230 url: url,
2231 test_verify_cert: jQuery('#mainwp_managesites_verify_certificate').is(':checked') ? 1 : 0,
2232 ssl_version: jQuery('#mainwp_managesites_add_ssl_version').val(),
2233 http_user: jQuery('#mainwp_managesites_add_http_user').val(),
2234 http_pass: jQuery('#mainwp_managesites_add_http_pass').val()
2235 });
2236
2237 jQuery.post(ajaxurl, data, function (response) { // NOSONAR - complex.
2238 jQuery('#mainwp-test-connection-modal .dimmer').hide();
2239 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').removeClass('red green check times');
2240 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html('');
2241 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html('');
2242 if (response.error) {
2243 if (response.httpCode) {
2244 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2245 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2246 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection failed!'));
2247 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + ' - ' + MainWP.I18n.t('HTTP-code:') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : '') + ' - ' + MainWP.I18n.t('Error message: ') + ' ' + response.error);
2248 } else {
2249 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2250 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2251 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2252 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('Error message:') + ' ' + response.error);
2253 }
2254 } else if (response.httpCode) {
2255 if (response.httpCode == '200') {
2256 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2257 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('green check');
2258 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection successful!'));
2259 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + (response.ip === undefined ? '' : ' (IP: ' + response.ip + ')') + ' - ' + MainWP.I18n.t('Received HTTP-code') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : ''));
2260 } else {
2261 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2262 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2263 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2264 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + (response.ip === undefined ? '' : ' (IP: ' + response.ip + ')') + ' - ' + MainWP.I18n.t('Received HTTP-code:') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : ''));
2265 }
2266 } else {
2267 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show('');
2268 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2269 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2270 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('Invalid response from the server, please try again.'));
2271 }
2272 }, 'json');
2273 }
2274 };
2275
2276 // Test Connection (Edit Site Page)
2277 let mainwp_managesites_edit_test = function () {
2278
2279 let clean_url = jQuery('#mainwp_managesites_edit_siteurl').val();
2280 let protocol = jQuery('#mainwp_managesites_edit_siteurl_protocol').val();
2281 let with_www = jQuery('input[name=mainwp_managesites_edit_wpurl_with_www]').val();
2282 with_www = with_www === 'www' ? with_www + '.' : '';
2283
2284 let url = protocol + '://' + with_www + clean_url;
2285
2286 if (!url.endsWith('/')) {
2287 url += '/';
2288 }
2289
2290 jQuery('#mainwp-test-connection-modal').modal('setting', 'closable', false).modal('show');
2291 jQuery('#mainwp-test-connection-modal .dimmer').show();
2292 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').hide();
2293
2294 let data = mainwp_secure_data({
2295 action: 'mainwp_testwp',
2296 url: url,
2297 test_verify_cert: jQuery('#mainwp_managesites_edit_verifycertificate').val(),
2298 ssl_version: jQuery('#mainwp_managesites_edit_ssl_version').val(),
2299 http_user: jQuery('#mainwp_managesites_edit_http_user').val(),
2300 http_pass: jQuery('#mainwp_managesites_edit_http_pass').val()
2301 });
2302
2303 jQuery.post(ajaxurl, data, function (response) { // NOSONAR - complex.
2304 jQuery('#mainwp-test-connection-modal .dimmer').hide();
2305 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').removeClass('red green check times');
2306 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html('');
2307 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html('');
2308 if (response.error) {
2309 if (response.httpCode) {
2310 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2311 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2312 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection failed!'));
2313 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + ' - ' + MainWP.I18n.t('HTTP-code:') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : '') + ' - ' + MainWP.I18n.t('Error message: ') + ' ' + response.error);
2314 } else {
2315 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2316 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2317 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2318 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('Error message:') + ' ' + response.error);
2319 }
2320 } else if (response.httpCode) {
2321 if (response.httpCode == '200') {
2322 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2323 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('green check');
2324 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection successful!'));
2325 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + (response.ip === undefined ? '' : ' (IP: ' + response.ip + ')') + ' - ' + MainWP.I18n.t('Received HTTP-code') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : ''));
2326 } else {
2327 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show();
2328 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2329 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2330 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('URL:') + ' ' + response.host + (response.ip === undefined ? '' : ' (IP: ' + response.ip + ')') + ' - ' + MainWP.I18n.t('Received HTTP-code:') + ' ' + response.httpCode + (response.httpCodeString ? ' (' + response.httpCodeString + ')' : ''));
2331 }
2332 } else {
2333 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result').show('');
2334 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result i').addClass('red times');
2335 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content span').html(MainWP.I18n.t('Connection test failed.'));
2336 jQuery('#mainwp-test-connection-modal .content #mainwp-test-connection-result .content .sub.header').html(MainWP.I18n.t('Invalid response from the server, please try again.'));
2337 }
2338 }, 'json');
2339 };
2340
2341 let managesites_remove = function (obj) {
2342 managesites_init();
2343
2344 let name = jQuery(obj).attr('site-name');
2345 let id = jQuery(obj).attr('site-id');
2346
2347 let msg = MainWP.I18n.t('Are you sure you want to remove') + ' ' + name + ' ' + MainWP.I18n.t('from your MainWP Dashboard?');
2348
2349 mainwp_confirm(msg, function () {
2350 jQuery('tr#child-site-' + id).html('<td colspan="999"><i class="notched circle loading icon"></i> ' + 'Removing and deactivating the MainWP Child plugin! Please wait...' + '</td>');
2351 let data = mainwp_secure_data({
2352 action: 'mainwp_removesite',
2353 id: id
2354 });
2355
2356 jQuery.post(ajaxurl, data, function (response) {
2357
2358 managesites_init();
2359
2360 let result = '';
2361 let error = '';
2362
2363 if (response.error != undefined) {
2364 error = response.error;
2365 } else if (response.result == 'SUCCESS') {
2366 result = '<i class="close icon"></i>' + MainWP.I18n.t('The site has been removed and the MainWP Child plugin has been disabled.');
2367 } else if (response.result == 'NOSITE') {
2368 error = '<i class="close icon"></i>' + MainWP.I18n.t('The requested site has not been found.');
2369 } else {
2370 result = '<i class="close icon"></i>' + MainWP.I18n.t('The site has been removed. Please make sure that the MainWP Child plugin has been deactivated properly.');
2371 }
2372
2373 if (error != '') {
2374 feedback('mainwp-message-zone', error, 'red');
2375 }
2376
2377 if (result != '') {
2378 feedback('mainwp-message-zone', result, 'green');
2379 }
2380
2381 jQuery('tr#child-site-' + id).remove();
2382
2383 }, 'json');
2384 }, false, false, false, 'REMOVE');
2385 return false;
2386 };
2387
2388 jQuery(function () {
2389
2390 jQuery(document).on('click', '#mainwp_managesites_add', function () {
2391 mainwp_managesites_add();
2392 });
2393
2394 // Hanlde click submit form import website
2395 jQuery(document).on('click', '#mainwp_managesites_bulkadd', function () {
2396
2397 let error_messages = mainwp_managesites_import_handle_form_before_submit();
2398 // If there is an error, prevent submission and display the error
2399 if (error_messages.length > 0) {
2400 feedback('mainwp-message-zone', error_messages.join("<br/>"), "red");
2401 } else {
2402 jQuery('#mainwp_managesites_bulkadd_form').submit();
2403 }
2404 return false;
2405 });
2406
2407 // Trigger Connection Test (Add Site Page)
2408 jQuery(document).on('click', '#mainwp_managesites_test', function () {
2409 mainwp_managesites_test();
2410 });
2411
2412 // Trigger Connection Test (Edit Site Page)
2413 jQuery(document).on('click', '#mainwp_managesites_edit_test', function () {
2414 mainwp_managesites_edit_test();
2415 });
2416
2417 // Use detected URL (Edit Site Page): set the protocol and www selectors to the child-reported address; no autosave.
2418 jQuery(document).on('click', '#mainwp_managesites_edit_use_detected', function () {
2419 let scheme = jQuery(this).attr('data-scheme');
2420 let with_www = jQuery(this).attr('data-www');
2421 if (scheme === 'http' || scheme === 'https') {
2422 jQuery('#mainwp_managesites_edit_siteurl_protocol').dropdown('set selected', scheme);
2423 }
2424 if (with_www === 'www' || with_www === 'none-www') {
2425 jQuery('#mainwp-edit-site-edit-url-www').dropdown('set selected', with_www);
2426 }
2427 return false;
2428 });
2429
2430 // Handle submit add multi website
2431 jQuery(document).on('click', '#mainwp_managesites_add_multi_site', function () {
2432 let error_messages = [];
2433 let has_table_data = false;
2434 has_table_data = mainwp_managesites_validate_import_rows(error_messages, true);
2435 // If there is an error, prevent submission and display the error
2436 if (error_messages.length > 0 && !has_table_data) {
2437 feedback('mainwp-add-multi-new-site-message-zone', error_messages.join("<br/>"), "red");
2438 } else {
2439 jQuery('#mainwp_managesites_add_form').submit();
2440 }
2441 return false;
2442 });
2443
2444 // Handle click remove website on management webiste.
2445 jQuery(document).on('click', '#mainwp-managesites-remove-site', function () {
2446 jQuery('#mainwp-remove-site-button').trigger('click');
2447 });
2448 });
2449
2450 /**
2451 * Add new user
2452 */
2453 function mainwp_gen_passsword(len = 24) {
2454 const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+{}[]<>?';
2455 const arr = new Uint32Array(len);
2456 crypto.getRandomValues(arr);
2457 return Array.from(arr, x => chars[x % chars.length]).join('');
2458 }
2459
2460 jQuery('.mainwp-generate-password-button').on('click', function (e) {
2461 e.preventDefault();
2462 jQuery('#createuser #password, #mainwp-update-admin-password-form #password').val(mainwp_gen_passsword(24)).trigger('change');
2463 });
2464
2465 jQuery(function () {
2466 jQuery(document).on('click', '#bulk_add_createuser', function () {
2467 mainwp_createuser();
2468 });
2469 jQuery('#bulk_import_createuser').on('click', function () {
2470 mainwp_bulkupload_users();
2471 });
2472 });
2473
2474 let mainwp_createuser = function () {
2475 let cont = true;
2476 if (jQuery('#user_login').val() == '') {
2477 feedback('mainwp-message-zone', MainWP.I18n.t('Username field is required! Please enter a username.'), 'yellow');
2478 cont = false;
2479 }
2480
2481 if (jQuery('#email').val() == '') {
2482 feedback('mainwp-message-zone', MainWP.I18n.t('E-mail field is required! Please enter an email address.'), 'yellow');
2483 cont = false;
2484 }
2485
2486 if (jQuery('#password').val() == '') {
2487 feedback('mainwp-message-zone', MainWP.I18n.t('Password field is required! Please enter the wanted password or generate a random one.'), 'yellow');
2488 cont = false;
2489 }
2490
2491 let selected_sites = [];
2492 let selected_clients = [];
2493 let selected_groups = [];
2494
2495 if (jQuery('input[name="select_by"]').val() == 'site') {
2496 jQuery("input[name='selected_sites[]']:checked").each(function () {
2497 selected_sites.push(jQuery(this).val());
2498 });
2499 if (selected_sites.length == 0) {
2500 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or group or client.'), 'yellow');
2501 cont = false;
2502 }
2503 } else if (jQuery('input[name="select_by"]').val() == 'client') {
2504 jQuery("input[name='selected_clients[]']:checked").each(function () {
2505 selected_clients.push(jQuery(this).val());
2506 });
2507 if (selected_clients.length == 0) {
2508 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or group or client.'), 'yellow');
2509 cont = false;
2510 }
2511 } else {
2512 jQuery("input[name='selected_groups[]']:checked").each(function () {
2513 selected_groups.push(jQuery(this).val());
2514 });
2515 if (selected_groups.length == 0) {
2516 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or group or client.'), 'yellow');
2517 cont = false;
2518 }
2519 }
2520
2521 if (cont) {
2522 mainwp_set_message_zone('#mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Creating the user. Please wait...'), '', true);
2523 jQuery('#bulk_add_createuser').attr('disabled', 'disabled');
2524 const is_send_password = jQuery('#send_password').is(':checked') ? 1 : 0;
2525 //Add user via ajax!!
2526 let data = mainwp_secure_data({
2527 action: "mainwp_bulkadduser",
2528 select_by: jQuery("input[name='select_by']").val(),
2529 "selected_groups[]": selected_groups,
2530 "selected_sites[]": selected_sites,
2531 "selected_clients[]": selected_clients,
2532 user_login: jQuery("#user_login").val(),
2533 email: jQuery("#email").val(),
2534 url: jQuery("#url").val(),
2535 first_name: jQuery("#first_name").val(),
2536 last_name: jQuery("#last_name").val(),
2537 pass1: jQuery("#password").val(),
2538 pass2: jQuery("#password").val(),
2539 send_password: is_send_password,
2540 role: jQuery("#role").val(),
2541 });
2542
2543 jQuery.post(ajaxurl, data, function (response) {
2544 response = response.trim();
2545 mainwp_set_message_zone('#mainwp-message-zone');
2546 jQuery('#bulk_add_createuser').prop("disabled", false);
2547 if (response.substring(0, 5) == 'ERROR') {
2548 let responseObj = JSON.parse(response.substring(6));
2549 if (responseObj.error == undefined) {
2550 let errorMessageList = responseObj[1];
2551 let errorMessage = '';
2552 for (let iem of errorMessageList) {
2553 if (errorMessage != '') {
2554 errorMessage = errorMessage + "<br />";
2555 }
2556 errorMessage = errorMessage + iem;
2557 }
2558 if (errorMessage != '') {
2559 feedback('mainwp-message-zone', errorMessage, 'red');
2560 }
2561 }
2562 } else {
2563 jQuery('#mainwp-add-new-user-form').append(response);
2564 jQuery('#mainwp-creating-new-user-modal').modal({
2565 closable: false,
2566 }).modal('show');
2567 }
2568 });
2569 }
2570 };
2571
2572 /**
2573 * InstallPlugins/Themes
2574 */
2575 jQuery(function () {
2576 jQuery('#MainWPInstallBulkNavSearch').on('click', function (event) {
2577 event.preventDefault();
2578 jQuery('#mainwp_plugin_bulk_install_btn').attr('bulk-action', 'install');
2579 jQuery('.mainwp-bulk-install-showhide-content').hide();
2580 jQuery('.mainwp-browse-plugins').show();
2581 jQuery('#mainwp-search-plugins-form').show();
2582 jQuery('.mainwp-bulk-install-tabs-header-btn').removeClass('green');
2583 jQuery(this).addClass('green');
2584 });
2585 jQuery('#MainWPInstallBulkNavUpload').on('click', function (event) {
2586 event.preventDefault();
2587 jQuery('#mainwp_plugin_bulk_install_btn').attr('bulk-action', 'upload');
2588 jQuery('.mainwp-bulk-install-showhide-content').hide();
2589 jQuery('.mainwp-upload-plugin').show();
2590 jQuery('.mainwp-bulk-install-tabs-header-btn').removeClass('green');
2591 jQuery(this).addClass('green');
2592 });
2593
2594 // not used?
2595 jQuery(document).on('click', '.filter-links li.plugin-install a', function (event) {
2596 event.preventDefault();
2597 jQuery('.filter-links li.plugin-install a').removeClass('current');
2598 jQuery(this).addClass('current');
2599 let tab = jQuery(this).parent().attr('tab');
2600 if (tab == 'search') {
2601 mainwp_install_search(event);
2602 } else {
2603 jQuery('#mainwp_installbulk_s').val('');
2604 jQuery('#mainwp_installbulk_tab').val(tab);
2605 mainwp_install_plugin_tab_search('tab:' + tab);
2606 }
2607 });
2608
2609 jQuery(document).on('click', '#mainwp_plugin_bulk_install_btn', function () {
2610 let act = jQuery(this).attr('bulk-action');
2611 if (act == 'install') {
2612 let selected = jQuery("input[type='radio'][name='install-plugin']:checked");
2613 if (selected.length == 0) {
2614 feedback('mainwp-message-zone', MainWP.I18n.t('Please select plugin to install files.'), 'yellow');
2615 } else {
2616 let selectedId = /^install-([^-]*)-(.*)$/.exec(selected.attr('id'));
2617 if (selectedId) {
2618 mainwp_install_bulk('plugin', selectedId[2], selected.attr('plugin-name'));
2619 }
2620 }
2621 } else if (act == 'upload') {
2622 mainwp_upload_bulk('plugins');
2623 }
2624
2625 return false;
2626 });
2627
2628 jQuery(document).on('click', '#mainwp_theme_bulk_install_btn', function () {
2629 let act = jQuery(this).attr('bulk-action');
2630 if (act == 'install') {
2631 let selected = jQuery("input[type='radio'][name='install-theme']:checked");
2632 if (selected.length == 0) {
2633 feedback('mainwp-message-zone', MainWP.I18n.t('Please select theme to install files.'), 'yellow');
2634 } else {
2635 let selectedId = /^install-([^-]*)-(.*)$/.exec(selected.attr('id'));
2636 if (selectedId)
2637 mainwp_install_bulk('theme', selectedId[2], selected.attr('theme-name'));
2638 }
2639 } else if (act == 'upload') {
2640 mainwp_upload_bulk('themes');
2641 }
2642 return false;
2643 });
2644 });
2645
2646 // Generate the Go to WP Admin link
2647 globalThis.mainwp_links_visit_site_and_admin = function (url, siteId) {
2648 let links = '';
2649 if (url != '') {
2650 links += '<a href="' + url + '" target="_blank" class="mainwp-may-hide-referrer"><i class="external alternate icon"></i></a> ';
2651 }
2652 links += '<a href="admin.php?page=SiteOpen&newWindow=yes&websiteid=' + siteId + '&_opennonce=' + mainwpParams._wpnonce + '" target="_blank"><i class="sign in alternate icon"></i></a>';
2653 return links;
2654 }
2655
2656 mainwpVars.bulkInstallTotal = 0;
2657 bulkInstallDone = 0;
2658
2659 /**
2660 * Install Plugin/Theme from WP.org.
2661 *
2662 * Initiate the process.
2663 *
2664 * @param string type Plugin or theme.
2665 * @param string slug Plugin or theme slug.
2666 *
2667 * @return void
2668 */
2669 let mainwp_install_bulk = function (type, slug, name) {
2670 let data = mainwp_secure_data({
2671 action: 'mainwp_preparebulkinstallplugintheme',
2672 type: type,
2673 slug: slug,
2674 name: name,
2675 selected_by: jQuery('input[name="select_by"]').val()
2676 });
2677 let placeholder = '<div class="ui placeholder"><div class="paragraph"><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div></div></div>';
2678
2679 if (jQuery('input[name="select_by"]').val() == 'site') {
2680
2681 let selected_sites = [];
2682
2683 jQuery("input[name='selected_sites[]']:checked").each(function () {
2684 selected_sites.push(jQuery(this).val());
2685 });
2686
2687 if (selected_sites.length == 0) {
2688 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2689 return;
2690 }
2691
2692 data['selected_sites[]'] = selected_sites;
2693
2694 } else if (jQuery('input[name="select_by"]').val() == 'client') {
2695
2696 let selected_clients = [];
2697
2698 jQuery("input[name='selected_clients[]']:checked").each(function () {
2699 selected_clients.push(jQuery(this).val());
2700 });
2701
2702 if (selected_clients.length == 0) {
2703 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2704 return;
2705 }
2706
2707 data['selected_clients[]'] = selected_clients;
2708
2709 } else {
2710 let selected_groups = [];
2711
2712 jQuery("input[name='selected_groups[]']:checked").each(function () {
2713 selected_groups.push(jQuery(this).val());
2714 });
2715
2716 if (selected_groups.length == 0) {
2717 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2718 return;
2719 }
2720
2721 data['selected_groups[]'] = selected_groups;
2722
2723 }
2724
2725 jQuery('#plugintheme-installation-queue').html(placeholder);
2726 jQuery.post(ajaxurl, data, function (type, activatePlugin, overwrite) {
2727 return function (response) {
2728 let installQueueContent = '';
2729 bulkInstallDone = 0;
2730 installQueueContent += '<div id="bulk_install_info"></div>';
2731 installQueueContent += '<div class="ui middle aligned divided list">';
2732
2733 for (let siteId in response.sites) {
2734 let site = response.sites[siteId];
2735 installQueueContent +=
2736 '<div class="siteBulkInstall item" siteid="' + siteId + '" status="queue">' +
2737 '<div class="right floated content">' +
2738 '<span class="queue" data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Queued') + '"><i class="clock outline icon"></i></span>' +
2739 '<span class="progress" data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Installing...') + '" style="display:none"><i class="notched circle loading icon"></i></span>' +
2740 '<span class="status"></span>' +
2741 '</div>' +
2742 '<div class="content">' + mainwp_links_visit_site_and_admin('', siteId) + ' ' + '<a href="' + site['url'] + '">' + site.name.replace(/\\(.)/g, '$1') + '</a></div>' + // NOSONAR - no safe replaceAll alternative.
2743 '</div>';
2744 mainwpVars.bulkInstallTotal++;
2745 }
2746
2747 installQueueContent += '</div>';
2748
2749 jQuery('#plugintheme-installation-queue').html(installQueueContent);
2750 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').progress({ value: 0, total: mainwpVars.bulkInstallTotal });
2751 mainwp_install_bulk_start_next(type, response.url, activatePlugin, overwrite, slug, response);
2752 }
2753 }(type, jQuery('#chk_activate_plugin').is(':checked'), jQuery('#chk_overwrite').is(':checked')), 'json');
2754
2755 jQuery('#plugintheme-installation-progress-modal').modal('setting', 'closable', false).modal('show');
2756
2757 };
2758
2759
2760 /**
2761 * Install Plugin/Theme from WP.org.
2762 *
2763 * Loop through sites.
2764 *
2765 * @param string type Plugin or theme.
2766 * @param string url URL.
2767 * @param bool activatePlugin Determines if the item should be activated or not upon installation.
2768 * @param bool overwrite Determines if the item should overwrite exisitng version.
2769 *
2770 * @return void
2771 */
2772 let mainwp_install_bulk_start_next = function (type, url, activatePlugin, overwrite, slug, installResults) { // NOSONAR - complex.
2773 while ((siteToInstall = jQuery('.siteBulkInstall[status="queue"]:first')) && (siteToInstall.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR - modified outside the function.
2774 mainwp_install_bulk_start_specific(type, url, activatePlugin, overwrite, siteToInstall, slug, installResults);
2775 }
2776 if (bulkInstallDone == mainwpVars.bulkInstallTotal && mainwpVars.bulkInstallTotal != 0) {
2777 jQuery('#bulk_install_info').before('<div class="ui info message">' + mainwp_install_bulk_you_know_msg(type, 1) + '</div>');
2778 if (jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').length > 0) { // to support add to cost tracker pro.
2779 if (installResults.add_to_cost_tracker_id != undefined) {
2780 if (installResults.add_to_cost_tracker_id > 0) {
2781 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').text(_('Edit Cost Tracker'));
2782 jQuery('#mainwp-cost-tracker-assistant-add-to-tracker-modal .header').text(_('Edit Cost Tracker'));
2783 }
2784 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('disabled', false);
2785 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').removeClass('disabled');
2786 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('item-slug', slug);
2787 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('item-type', type);
2788 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('item-name', installResults.name);
2789 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('cost-id', installResults.add_to_cost_tracker_id);
2790 if (installResults.installed_sites != undefined) {
2791 jQuery('.mainwp-cost-tracker-assistant-add-to-cost-tracker-button').attr('installed-sites', installResults.installed_sites.join(','));
2792 }
2793 }
2794 }
2795 }
2796 };
2797
2798 /**
2799 * Install Plugin/Theme from WP.org.
2800 *
2801 * Install specific item.
2802 *
2803 * @param string type Plugin or theme.
2804 * @param string url URL.
2805 * @param bool activatePlugin Determines if the item should be activated or not upon installation.
2806 * @param bool overwrite Determines if the item should overwrite exisitng version.
2807 * @param object siteToInstall Site to install the item to.
2808 *
2809 * @return void
2810 */
2811 let mainwp_install_bulk_start_specific = function (type, url, activatePlugin, overwrite, siteToInstall, slug, installResults) {
2812 bulkInstallCurrentThreads++;
2813
2814 siteToInstall.attr('status', 'progress');
2815 siteToInstall.find('.queue').hide();
2816 siteToInstall.find('.progress').show();
2817 let data = mainwp_secure_data({
2818 action: 'mainwp_installbulkinstallplugintheme',
2819 type: type,
2820 url: url,
2821 activatePlugin: activatePlugin,
2822 overwrite: overwrite,
2823 siteId: siteToInstall.attr('siteid')
2824 });
2825
2826 jQuery.post(ajaxurl, data, function (type, url, activatePlugin, overwrite, siteToInstall) {
2827 return function (response) {
2828 siteToInstall.attr('status', 'done');
2829 siteToInstall.find('.progress').hide();
2830 let statusEl = siteToInstall.find('.status');
2831 statusEl.show();
2832 let _error = '';
2833 if (response.error != undefined) {
2834 statusEl.html(response.error);
2835 statusEl.css('color', 'red');
2836 } else if (response?.ok[siteToInstall.attr('siteid')]) {
2837 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Installation completed successfully.') + '"><i class="check green icon"></i></span>');
2838 if (installResults.installed_sites == undefined) {
2839 installResults.installed_sites = [];
2840 }
2841 installResults.installed_sites.push(siteToInstall.attr('siteid'));
2842 } else if (response?.errors[siteToInstall.attr('siteid')]) {
2843 _error = response.errors[siteToInstall.attr('siteid')][1];
2844 } else {
2845 _error = MainWP.I18n.t('Undefined error occurred. Please try again.');
2846 }
2847
2848 if (_error !== '') {
2849 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + _error + '"><i class="times red icon"></i></span>');
2850 }
2851
2852 bulkInstallCurrentThreads--;
2853 bulkInstallDone++;
2854
2855 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').progress('set progress', bulkInstallDone);
2856 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').find('.label').html(bulkInstallDone + '/' + mainwpVars.bulkInstallTotal + ' ' + MainWP.I18n.t('Installed'));
2857 mainwp_install_bulk_start_next(type, url, activatePlugin, overwrite, slug, installResults);
2858 }
2859 }(type, url, activatePlugin, overwrite, siteToInstall), 'json');
2860 };
2861
2862
2863 let mainwp_install_bulk_you_know_msg = function (type, total) { // NOSONAR - complex.
2864 let msg = '';
2865 if (mainwpParams.installedBulkSettingsManager && mainwpParams.installedBulkSettingsManager == 1) {
2866 if (type == 'plugin') {
2867 if (total == 1)
2868 msg = MainWP.I18n.t('Would you like to use the Bulk Settings Manager with this plugin? Check out the %1Documentation%2.', '<a href="https://docs.mainwp.com/add-ons/administrative/bulk-settings-manager-extension" target="_blank">', '</a>'); // NOSONAR - noopener - open safe.
2869 else
2870 msg = MainWP.I18n.t('Would you like to use the Bulk Settings Manager with these plugins? Check out the %1Documentation%2.', '<a href="https://docs.mainwp.com/add-ons/administrative/bulk-settings-manager-extension" target="_blank">', '</a>'); // NOSONAR - noopener - open safe.
2871 } else if (type == 'theme') {
2872 if (total == 1)
2873 msg = MainWP.I18n.t('Would you like to use the Bulk Settings Manager with this theme? Check out the %1Documentation%2.', '<a href="https://docs.mainwp.com/add-ons/administrative/bulk-settings-manager-extension" target="_blank">', '</a>'); // NOSONAR - noopener - open safe.
2874 else
2875 msg = MainWP.I18n.t('Would you like to use the Bulk Settings Manager with these themes? Check out the %1Documentation%2.', '<a href="https://docs.mainwp.com/add-ons/administrative/bulk-settings-manager-extension" target="_blank">', '</a>'); // NOSONAR - noopener - open safe.
2876 }
2877 } else if (type == 'plugin') {
2878 if (total == 1)
2879 msg = MainWP.I18n.t('Did you know with the %1 you can control the settings of this plugin directly from your MainWP Dashboard?', '<a href="https://mainwp.com/add-on/bulk-settings-manager/" target="_blank">Bulk Settings Extension</a>'); // NOSONAR - noopener - open safe.
2880 else
2881 msg = MainWP.I18n.t('Did you know with the %1 you can control the settings of these plugins directly from your MainWP Dashboard?', '<a href="https://mainwp.com/add-on/bulk-settings-manager/" target="_blank">Bulk Settings Extension</a>'); // NOSONAR - noopener - open safe.
2882 } else if (type == 'theme') {
2883 if (total == 1)
2884 msg = MainWP.I18n.t('Did you know with the %1 you can control the settings of this theme directly from your MainWP Dashboard?', '<a href="https://mainwp.com/add-on/bulk-settings-manager/" target="_blank">Bulk Settings Extension</a>'); // NOSONAR - noopener - open safe.
2885 else
2886 msg = MainWP.I18n.t('Did you know with the %1 you can control the settings of these themes directly from your MainWP Dashboard?', '<a href="https://mainwp.com/add-on/bulk-settings-manager/" target="_blank">Bulk Settings Extension</a>'); // NOSONAR - noopener - open safe.
2887 }
2888 return msg;
2889 }
2890
2891 /**
2892 * Install Plugin/Theme by Upload.
2893 *
2894 * Initiate the process.
2895 *
2896 * @param string type Plugin or theme.
2897 *
2898 * @return void
2899 */
2900 let mainwp_upload_bulk = function (type) {
2901
2902 if (type == 'plugins') {
2903 type = 'plugin';
2904 } else {
2905 type = 'theme';
2906 }
2907
2908 let files = [];
2909
2910 jQuery(".qq-upload-file").each(function () {
2911 if (jQuery(this).closest('.file-uploaded-item').hasClass('qq-upload-success')) {
2912 files.push(jQuery(this).attr('filename'));
2913 }
2914 });
2915
2916 if (files.length == 0) {
2917 if (type == 'plugin') {
2918 feedback('mainwp-message-zone', MainWP.I18n.t('Please upload at least one plugin to install.'), 'yellow');
2919 } else {
2920 feedback('mainwp-message-zone', MainWP.I18n.t('Please upload at least one theme to install.'), 'yellow');
2921 }
2922 return;
2923 }
2924
2925 let data = mainwp_secure_data({
2926 action: 'mainwp_preparebulkuploadplugintheme',
2927 type: type,
2928 selected_by: jQuery('input[name="select_by"]').val()
2929 });
2930
2931 let placeholder = '<div class="ui placeholder"><div class="paragraph"><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div></div></div>';
2932
2933 if (jQuery('input[name="select_by"]').val() == 'site') {
2934 let selected_sites = [];
2935 jQuery("input[name='selected_sites[]']:checked").each(function () {
2936 selected_sites.push(jQuery(this).val());
2937 });
2938
2939 if (selected_sites.length == 0) {
2940 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2941 return;
2942 }
2943 data['selected_sites[]'] = selected_sites;
2944 } else if (jQuery('input[name="select_by"]').val() == 'client') {
2945 let selected_clients = [];
2946 jQuery("input[name='selected_clients[]']:checked").each(function () {
2947 selected_clients.push(jQuery(this).val());
2948 });
2949
2950 if (selected_clients.length == 0) {
2951 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2952 return;
2953 }
2954 data['selected_clients[]'] = selected_clients;
2955 } else {
2956 let selected_groups = [];
2957 jQuery("input[name='selected_groups[]']:checked").each(function () {
2958 selected_groups.push(jQuery(this).val());
2959 });
2960 if (selected_groups.length == 0) {
2961 feedback('mainwp-message-zone', MainWP.I18n.t('Please select at least one website or a group or client.'), 'yellow');
2962 return;
2963 }
2964 data['selected_groups[]'] = selected_groups;
2965 }
2966
2967 data['files[]'] = files;
2968
2969 jQuery('#plugintheme-installation-queue').html(placeholder);
2970
2971 jQuery.post(ajaxurl, data, function (type, files, activatePlugin, overwrite) {
2972 return function (response) {
2973 let installQueue = '';
2974 mainwpVars.bulkInstallTotal = 0;
2975 bulkInstallDone = 0;
2976
2977 installQueue += '<div class="ui middle aligned selection divided list">';
2978
2979 for (let siteId in response.sites) {
2980 let site = response.sites[siteId];
2981
2982 installQueue +=
2983 '<div class="siteBulkInstall item" siteid="' + siteId + '" status="queue">' +
2984 '<div class="right floated content">' +
2985 '<span class="queue" data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Queued') + '"><i class="clock outline icon"></i></span>' +
2986 '<span class="progress" data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Installing...') + '" style="display:none"><i class="notched circle loading icon"></i></span>' +
2987 '<span class="status"></span>' +
2988 '</div>' +
2989 '<div class="content">' + mainwp_links_visit_site_and_admin('', siteId) + ' ' + '<a href="' + site['url'] + '">' + site.name.replace(/\\(.)/g, '$1') + '</a></div>' + // NOSONAR - no safe replaceAll alternative.
2990 '<div class="installation-entries"></div>' +
2991 '</div>';
2992 mainwpVars.bulkInstallTotal++;
2993 }
2994
2995 installQueue += '</div>';
2996
2997 jQuery('#plugintheme-installation-queue').html(installQueue);
2998
2999 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').progress({ value: 0, total: mainwpVars.bulkInstallTotal });
3000 mainwp_upload_bulk_start_next(type, response.urls, activatePlugin, overwrite);
3001 }
3002 }(type, files, jQuery('#chk_activate_plugin').is(':checked'), jQuery('#chk_overwrite').is(':checked')), 'json');
3003
3004 jQuery('#plugintheme-installation-progress-modal').modal('setting', 'closable', false).modal('show');
3005
3006 jQuery('.qq-upload-list').html(''); // empty files list!
3007
3008 return false;
3009 };
3010
3011 /**
3012 * Install Plugin/Theme by Upload.
3013 *
3014 * Loop through sites.
3015 *
3016 * @param string type Plugin or theme.
3017 * @param string urls URLs.
3018 * @param bool activatePlugin Determines if the item should be activated or not upon installation.
3019 * @param bool overwrite Determines if the item should overwrite exisitng version.
3020 *
3021 * @return void
3022 */
3023 let mainwp_upload_bulk_start_next = function (type, urls, activatePlugin, overwrite) {
3024 while ((siteToInstall = jQuery('.siteBulkInstall[status="queue"]:first')) && (siteToInstall.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR - modified outside the function.
3025 mainwp_upload_bulk_start_specific(type, urls, activatePlugin, overwrite, siteToInstall);
3026 }
3027
3028 if ((siteToInstall.length == 0) && (bulkInstallCurrentThreads == 0)) { // NOSONAR - modified outside the function.
3029 let data = mainwp_secure_data({
3030 action: 'mainwp_cleanbulkuploadplugintheme',
3031 });
3032
3033 jQuery.post(ajaxurl, data, function () {
3034 jQuery('.file-uploaded-item.qq-upload-completed').remove();
3035 });
3036
3037 let msg = mainwp_install_bulk_you_know_msg(type, jQuery('#bulk_upload_info').attr('number-files'));
3038
3039 jQuery('#bulk_upload_info').html('<div class="bui blue message">' + msg + '</div>');
3040
3041 if (jQuery('.mainwp_cost_tracker_assistant_installed_items').length > 0) { // to support add to cost tracker pro.
3042 let cost_tracker_items = [];
3043 let cost_tracker_check_slugs = [];
3044 jQuery('.mainwp_cost_tracker_assistant_installed_items').each(function () {
3045 let slug = jQuery(this).attr('item-slug');
3046 let items_slug = {};
3047 if (!cost_tracker_check_slugs.includes(slug)) {
3048 cost_tracker_check_slugs.push(slug);
3049 let siteids = [];
3050 jQuery('.mainwp_cost_tracker_assistant_installed_items[item-slug="' + slug + '"]').each(function () {
3051 siteids.push(jQuery(this).attr('item-siteid'));
3052 });
3053 items_slug.slug = slug;
3054 items_slug.name = jQuery(this).attr('item-name');
3055 items_slug.type = jQuery(this).attr('item-type');
3056 items_slug.cost_id = jQuery(this).attr('cost-id');
3057 items_slug.sites_ids = siteids;
3058 cost_tracker_items.push(items_slug);
3059 }
3060 });
3061
3062 if (cost_tracker_items.length > 0) {
3063 jQuery('.mainwp-cost-tracker-assistant-add-buttons-wrapper').html('');
3064 let multiAddTo = cost_tracker_items.length > 1 ? 1 : 0;
3065 cost_tracker_items.forEach(item => {
3066 jQuery('.mainwp-cost-tracker-assistant-add-buttons-wrapper').append('<a href="javascript:void(0)" item-type="' + item.type + '" item-slug="' + item.slug + '" cost-id="' + item.cost_id + '" item-name="' + item.name + '" installed-sites="' + item.sites_ids.join(',') + '" multi-add-to="' + multiAddTo + '" class="ui mini button mainwp-cost-tracker-assistant-add-to-cost-tracker-button">' + ((item.cost_id != undefined && item.cost_id > 0) ? MainWP.I18n.t('Edit Cost Tracker') + ' (' + item.name + ')' : MainWP.I18n.t('Add to Cost Tracker') + ' (' + item.name + ')') + '</a>');
3067 });
3068 }
3069 }
3070 }
3071 };
3072
3073 /**
3074 * Install Plugin/Theme by Upload.
3075 *
3076 * Install specific item.
3077 *
3078 * @param string type Plugin or theme.
3079 * @param string urls URLs.
3080 * @param bool activatePlugin Determines if the item should be activated or not upon installation.
3081 * @param bool overwrite Determines if the item should overwrite exisitng version.
3082 * @param object siteToInstall Site to install the item to.
3083 *
3084 * @return void
3085 */
3086 let mainwp_upload_bulk_start_specific = function (type, urls, activatePlugin, overwrite, siteToInstall) {
3087 bulkInstallCurrentThreads++;
3088 siteToInstall.attr('status', 'progress');
3089
3090 siteToInstall.find('.queue').hide();
3091 siteToInstall.find('.progress').show();
3092
3093 let data = mainwp_secure_data({
3094 action: 'mainwp_installbulkuploadplugintheme',
3095 type: type,
3096 urls: urls,
3097 activatePlugin: activatePlugin,
3098 overwrite: overwrite,
3099 siteId: siteToInstall.attr('siteid')
3100 });
3101
3102 jQuery.post(ajaxurl, data, function (type, urls, activatePlugin, overwrite, siteToInstall) {
3103 return function (response) {
3104 siteToInstall.attr('status', 'done');
3105 siteToInstall.find('.progress').hide();
3106 let statusEl = siteToInstall.find('.status');
3107 let siteid = siteToInstall.attr('siteid');
3108 statusEl.show();
3109
3110 if (response.error != undefined) {
3111 statusEl.html(response.error);
3112 statusEl.css('color', 'red');
3113 } else if (response?.ok[siteid] != undefined) {
3114 let results = '';
3115 if (response?.results[siteid] != undefined) {
3116 let entries = Object.entries(response.results[siteid]);
3117 results += '<div class="ui tiny middle aligned list">';
3118 for (let entry of entries) {
3119 results += '<div class="item"><div class="right floated content">' + (entry[1] ? '<i class="check green icon"></i>' : '<i class="times red icon"></i>') + '</div><div class="content">' + entry[0] + '</div></div>';
3120 }
3121 results += '</div>';
3122 }
3123 jQuery('div[siteId="' + siteid + '"] .installation-entries').html(results);
3124 if (response.cost_tracker_installed_info != undefined) { // to support add to cost tracker pro.
3125 jQuery('div[siteId="' + siteid + '"] .installation-entries').after(response.cost_tracker_installed_info);
3126 }
3127 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Installation completed successfully.') + '"><i class="check green icon"></i></span>');
3128 } else if (response?.errors[siteid] === undefined) {
3129 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Undefined error occurred. Please try again.') + '"><i class="times red icon"></i></span>');
3130 } else {
3131 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + response.errors[siteid][1] + '"><i class="times red icon"></i></span>');
3132 }
3133
3134 bulkInstallCurrentThreads--;
3135 bulkInstallDone++;
3136 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').progress('set progress', bulkInstallDone);
3137 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').find('.label').html(bulkInstallDone + '/' + mainwpVars.bulkInstallTotal + ' ' + MainWP.I18n.t('Installed'));
3138 mainwp_upload_bulk_start_next(type, urls, activatePlugin, overwrite);
3139 }
3140 }(type, urls, activatePlugin, overwrite, siteToInstall), 'json');
3141 };
3142
3143 jQuery(function ($) {
3144 jQuery(document).on('click', '.open-plugin-details-modal', (event) => {
3145
3146 const $el = jQuery(event.currentTarget);
3147
3148 const openwpp = $el.attr('open-wpplugin');
3149 let openwpp_site = '';
3150
3151 if (openwpp === 'yes') {
3152 const findNext = $el
3153 .closest('tr')
3154 .next()
3155 .find('tr[open-wpplugin-siteid]');
3156
3157 if (findNext.length > 0) {
3158 openwpp_site =
3159 '&wpplugin=' + findNext.attr('open-wpplugin-siteid');
3160 }
3161 }
3162
3163 $('#mainwp-plugin-details-modal')
3164 .modal({
3165 onHide: function () { },
3166 onShow: () => {
3167 $('#mainwp-plugin-details-modal')
3168 .find('.ui.embed')
3169 .embed({
3170 source: 'WP',
3171 url: $el.attr('href') + openwpp_site,
3172 });
3173 }
3174 })
3175 .modal('show');
3176
3177 return false;
3178 });
3179 });
3180
3181
3182 /**
3183 *
3184 * Widget plugins/themes changes history
3185 *
3186 */
3187
3188 let pluginChangesLoadData = {};
3189 let themeChangesLoadData = {};
3190
3191 jQuery(function ($) {
3192
3193 $(document).on('click', '.mainwp-show-history', function (e) {
3194
3195 e.preventDefault();
3196 e.stopPropagation();
3197
3198 const view = $(this).attr('history-view');
3199 let parent = false;
3200 let type = 'plugin'; // default.
3201 let title = '';
3202 let info = '';
3203 let name = '';
3204 let slug = '';
3205 let siteId = 0;
3206
3207 switch (view) {
3208 case 'update-plugins-individual':
3209 parent = $(this).closest('.plugins-bulk-updates');
3210 siteId = $(parent).attr('site_id');
3211 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3212 title = $(this).closest('tr').attr('plugin_name');
3213 slug = decodeURIComponent($(this).closest('tr').attr('plugin_slug'));
3214 name = $(this).closest('tr').attr('plugin_name');
3215 break;
3216 case 'update-themes-individual':
3217 parent = $(this).closest('.themes-bulk-updates');
3218 siteId = $(parent).attr('site_id');
3219 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3220 title = $(this).closest('tr').attr('theme_name');
3221 slug = $(this).closest('tr').attr('theme_slug');
3222 name = $(this).closest('tr').attr('theme_name');
3223 type = 'theme';
3224 break;
3225 case 'manage-plugins-per-sites':
3226 case 'manage-plugins-per-items':
3227 parent = $(this).closest('.mainwp-manage-plugin-item-website');
3228 title = $(parent).attr('plugin-name');
3229 info = $(parent).attr('site-name') + ' (' + $(parent).attr('site-url') + ') ' + $(parent).attr('tz-info');
3230 slug = decodeURIComponent($(parent).attr('plugin-slug'));
3231 siteId = $(parent).attr('site-id');
3232 break;
3233 case 'manage-themes-per-sites':
3234 case 'manage-themes-per-items':
3235 parent = $(this).closest('.mainwp-manage-theme-item-website');
3236 title = $(parent).attr('theme-name');
3237 name = $(parent).attr('theme-name');
3238 info = $(parent).attr('site-name') + ' (' + $(parent).attr('site-url') + ') ' + $(parent).attr('tz-info');
3239 slug = decodeURIComponent($(parent).attr('theme-slug'));
3240 siteId = $(parent).attr('site-id');
3241 type = 'theme';
3242 break;
3243 case 'widget-plugins':
3244 parent = $(this).closest('.row-manage-item');
3245 title = $(parent).attr('plugin-name');
3246 info = $('#mainwp-widget-active-plugins').attr('site-info');
3247 slug = $(parent).attr('plugin-slug');
3248 siteId = $('#mainwp-widget-active-plugins').attr('site-id');
3249 break;
3250 case 'widget-themes':
3251 parent = $(this).closest('.row-manage-item');
3252 title = $(parent).find('.themeName').val();
3253 info = $('#mainwp-widget-inactive-themes').attr('site-info');
3254 slug = $(parent).find('.themeSlug').val();
3255 name = $(parent).find('.themeName').val();
3256 siteId = $('#mainwp-widget-inactive-themes').attr('site-id');
3257 type = 'theme';
3258 break;
3259 case 'update-plugin-per-item':
3260 parent = $(this).closest('tr');
3261 siteId = $(parent).attr('site_id');
3262 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3263 title = $(parent).attr('plugin_name');
3264 slug = decodeURIComponent($(parent).attr('plugin_slug'));
3265 break;
3266 case 'update-theme-per-item':
3267 parent = $(this).closest('tr');
3268 siteId = $(parent).attr('site_id');
3269 info = $(parent).attr('site_name') + ' (' + decodeURIComponent($(parent).attr('site_url')) + ') ' + $(parent).attr('tz-info');
3270 title = $(parent).attr('theme_name');
3271 name = $(parent).attr('theme_name');
3272 slug = decodeURIComponent($(parent).attr('theme_slug'));
3273 type = 'theme';
3274 break;
3275 case 'update-plugin-per-site': // NOSONAR - same as above.
3276 parent = $(this).closest('.plugins-bulk-updates');
3277 siteId = $(parent).attr('site_id');
3278 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3279 title = $(this).closest('tr').attr('plugin_name');
3280 slug = decodeURIComponent($(this).closest('tr').attr('plugin_slug'));
3281 name = $(this).closest('tr').attr('plugin_name');
3282 break;
3283 case 'update-theme-per-site': // NOSONAR - same above.
3284 parent = $(this).closest('.themes-bulk-updates');
3285 siteId = $(parent).attr('site_id');
3286 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3287 title = $(this).closest('tr').attr('theme_name');
3288 slug = $(this).closest('tr').attr('theme_slug');
3289 name = $(this).closest('tr').attr('theme_name');
3290 type = 'theme';
3291 break;
3292 case 'update-plugin-per-tag':
3293 parent = $(this).closest('.plugins-bulk-updates');
3294 siteId = $(parent).attr('site_id');
3295 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3296 title = $(this).closest('tr').attr('plugin_name');
3297 slug = decodeURIComponent($(this).closest('tr').attr('plugin_slug'));
3298 break;
3299 case 'update-theme-per-tag':
3300 parent = $(this).closest('.themes-bulk-updates');
3301 siteId = $(parent).attr('site_id');
3302 info = $(parent).attr('site_name') + ' (' + $(parent).attr('site_url') + ') ' + $(parent).attr('tz-info');
3303 title = $(this).closest('tr').attr('theme_name');
3304 name = $(this).closest('tr').attr('theme_name');
3305 slug = $(this).closest('tr').attr('theme_slug');
3306 type = 'theme';
3307 break;
3308 }
3309
3310 if (type === 'plugin') {
3311 pluginChangesLoadData = mainwp_secure_data({
3312 action: 'mainwp_changes_logs_get_item_changes',
3313 type: 'plugin',
3314 slug: slug,
3315 siteId: siteId,
3316 from_date: '' // current date.
3317 });
3318 } else if (type === 'theme') {
3319 themeChangesLoadData = mainwp_secure_data({
3320 action: 'mainwp_changes_logs_get_item_changes',
3321 type: 'theme',
3322 slug: slug,
3323 siteId: siteId,
3324 name: name,
3325 from_date: '' // current date.
3326 });
3327 }
3328
3329 $('#mainwp-plugin-theme-history-changes-modal').modal({
3330 onHide: function () {
3331 },
3332 onShow: function () {
3333 mainwp_changes_history_box_init(type, title, info);
3334 jQuery('#mainwp-plugin-theme-history-changes-modal').find('.content.ui').html('<div class="ui active centered inline loader history-actions-loading"></div>');
3335 mainwp_item_changes_load();
3336 }
3337 }).modal('show');
3338 });
3339 });
3340
3341 let mainwp_changes_history_box_init = function (type, title, info) {
3342 const hd = jQuery('#mainwp-plugin-theme-history-changes-modal > div.header');
3343 hd.find('.main-text').text(title + ' ' + MainWP.I18n.t('History')); // safe for escape.
3344 hd.find('.sub.header').text(info).show();
3345 jQuery('#mainwp-plugin-theme-history-changes-modal').attr('history-type', type);
3346 jQuery('#mainwp-plugin-theme-history-changes-modal').find('.scrolling.content').html('');
3347 }
3348
3349 let mainwp_item_changes_load = function (btnObj, load_more_date = '') {
3350
3351 let md = jQuery('#mainwp-plugin-theme-history-changes-modal');
3352 let parentContent = false;
3353 if (btnObj) {
3354 parentContent = jQuery(btnObj).closest('.ui.accordion').find('.ui.content');
3355 } else {
3356 parentContent = jQuery(md).find('.scrolling.content')
3357 }
3358
3359 jQuery(md).find('.actions .col-left').html('');
3360 jQuery(md).find('.actions .col-right').html('');
3361
3362 const type = jQuery(md).attr('history-type');
3363 let load_more = false;
3364
3365 // set load date if provided
3366 if (typeof load_more_date === 'string' && load_more_date !== '') {
3367 if ('theme' === type) {
3368 themeChangesLoadData.from_date = load_more_date;
3369 } else {
3370 pluginChangesLoadData.from_date = load_more_date;
3371 }
3372 load_more = true;
3373 }
3374
3375 let data = 'plugin' === type ? pluginChangesLoadData : themeChangesLoadData;
3376
3377
3378 jQuery.post(ajaxurl, data, function (response) { // NOSONAR - complex.
3379 jQuery(md).find('.history-actions-loading').remove();
3380 if (response?.error) {
3381 if (parentContent) {
3382 let err_content = '<div class="ui message red">' + response.error + '</div>';
3383 jQuery(parentContent).html(err_content);
3384 }
3385 } else if (response?.list) {
3386 if (response.list.length == 0) {
3387 let msg = MainWP.I18n.t('This plugin has no recorded activity in Dashboard Insights.');
3388 if ('theme' === type) {
3389 msg = MainWP.I18n.t('This theme has no recorded activity in Dashboard Insights.');
3390 }
3391 if (parentContent) {
3392 let msg_content = '<div class="ui info message">' + msg + '</div>';
3393 jQuery(parentContent).html(msg_content);
3394 }
3395 } else {
3396 let content = '';
3397 Object.entries(response.list).forEach(([indexdt, records]) => {
3398 const dt = records[0].date;
3399 content += `<div class="ui accordion" data-date="${indexdt}">
3400 <div class="title" format-date="${dt}">
3401 <div class="ui container">
3402 <div class="ui grid">
3403 <div class="ten wide column middle aligned">
3404 <i class="dropdown icon"></i>
3405 ${dt}
3406 </div>
3407 <div class="six wide column right aligned">
3408 <button type="button" class="ui circular blue mini button mainwp-day-history-switch-view">` + MainWP.I18n.t('Day History') + `</button> <button class="ui basic mini button actions-count1">${records.length} ` + MainWP.I18n.t('Actions') + `</button>
3409 </div>
3410 </div>
3411 </div>
3412 </div>
3413 <div class="content ui list">`;
3414 records.forEach(record => {
3415 content += `<div class="item" log-id="${record.details.log_id}">
3416 <div class="ui grid">
3417 <div class="eight wide column middle aligned">
3418 <i class="` + get_icon_history_event(record.details.action) + ` icon"></i>
3419 <span class="ui text ` + get_color_changes_event(record.details.action) + `">${record.details.event}</span> ` + MainWP.I18n.t('by') + ` <strong>${record.details.author_name}</strong> ` + MainWP.I18n.t('from') + `
3420 <strong>${record.details.source}</strong>
3421 </div>
3422 <div class="six wide column middle aligned">
3423 ` + (record.details?.old_version && record.details?.version ? record.details.old_version + '&rarr;' + record.details.version : '') + `
3424 </div>
3425 <div class="two wide column right aligned">
3426 ${record.details.at_hour}
3427 </div>
3428 </div>
3429 </div>`;
3430 });
3431 content += `</div>
3432 </div>`;
3433 });
3434
3435 if ('' !== content) {
3436 let accordWrapper = jQuery("<div>", {
3437 id: "change-history-according-wrapper",
3438 html: content
3439 });
3440
3441 let name_title = '';
3442
3443 if ((data?.name || data?.slug) && response?.name_title) {
3444 name_title = response.name_title;
3445 }
3446
3447 if (name_title != '') {
3448 jQuery(md).find('.ui.header .main-text').text(name_title + ' ' + MainWP.I18n.t('History'));
3449 }
3450
3451 if (load_more) {
3452 jQuery(md).find('.scrolling.content').append(accordWrapper);
3453 } else {
3454 jQuery(md).find('.scrolling.content').html(accordWrapper);
3455 }
3456
3457 jQuery('#change-history-according-wrapper .ui.accordion').accordion({ exclusive: true });
3458
3459 jQuery('.mainwp-day-history-switch-view').off('click.accordionFix').on('click.accordionFix', function (e) {
3460 e.preventDefault();
3461 e.stopPropagation(); // now it runs before ancestor handlers
3462 dayHistory_SwitchViewHandler(this);
3463 return false;
3464 });
3465 }
3466
3467 if (response?.onward_date) {
3468 jQuery(md).find('.actions .col-left').html('Data available from ' + response.onward_date + ' onward.');
3469 }
3470 if (response?.more_date) {
3471 jQuery(md).find('.actions .col-right').html('<a href="javascript:void(0);" onclick="mainwp_item_changes_load(false,\'' + (response.more_date ?? get_local_date_string()) + '\');return false;">' + MainWP.I18n.t('Load More') + '</a>');
3472 }
3473 }
3474 } else if (parentContent) {
3475 let err_content = '<div class="ui message red">' + MainWP.I18n.t('Undefined error occurred. Please try again.') + '</div>';
3476 jQuery(parentContent).html(err_content);
3477 }
3478 }, 'json');
3479 }
3480
3481 let get_icon_history_event = function (act) {
3482 let icon = '';
3483
3484 if (act === 'delete' || act === 'deleted') {
3485 icon = 'trash red';
3486 } else if (act === 'deactivated' || act === 'deactivate') {
3487 icon = 'toggle off red';
3488 } else if (act === 'activated' || act === 'activate') {
3489 icon = 'toggle on green';
3490 } else if (act === 'updated' || act === 'update') {
3491 icon = 'sync orange';
3492 } else if (act === 'installed' || act === 'install') {
3493 icon = 'download teal';
3494 } else {
3495 icon = 'circle grey';
3496 }
3497
3498 return icon;
3499 }
3500
3501 let get_color_changes_event = function (act) {
3502 const actColorMap = {
3503 red: ['deleted', 'removed', 'revoked', 'delete', 'deactivated', 'disabled', 'suspended', 'deactivate'],
3504 orange: ['updated', 'modified', 'update'],
3505 grey: ['opened'],
3506 blue: ['logged-in', 'logged-out'],
3507 teal: ['sync', 'installed', 'install', 'uploaded'],
3508 green: ['activated', 'activate', 'created', 'published', 'enabled', 'added']
3509 };
3510
3511 let color = '';
3512
3513 for (const [c, acts] of Object.entries(actColorMap)) {
3514 if (acts.includes(act)) {
3515 color = c;
3516 break;
3517 }
3518 }
3519 return color;
3520 }
3521
3522 let dayHistory_SwitchViewHandler = function (btn) {
3523
3524 const parent = jQuery(btn).closest('.ui.accordion');
3525 const his_date = jQuery(btn).closest('.title').attr('format-date');
3526
3527 jQuery(btn).closest('.title').hasClass('active') || jQuery(btn).closest('.title').trigger('click');
3528
3529 jQuery(parent).find('.content.ui').html('<div class="ui active centered inline loader history-actions-loading"></div>');
3530
3531 const dt = jQuery(parent).data('date');
3532 let md = jQuery('#mainwp-plugin-theme-history-changes-modal');
3533 const type = jQuery(md).attr('history-type');
3534
3535 let siteId = ('plugin' === type ? pluginChangesLoadData.siteId : themeChangesLoadData.siteId) || 0;
3536
3537 let data = mainwp_secure_data({
3538 action: 'mainwp_changes_logs_get_item_changes',
3539 type: type,
3540 target_date: dt,
3541 siteId: siteId
3542 });
3543
3544 jQuery.post(ajaxurl, data, function (response) { // NOSONAR - complex.
3545
3546 jQuery(parent).find('.history-actions-loading').remove();
3547
3548 let dayContent = jQuery(parent).find('.content');
3549
3550 if (response.error != undefined) {
3551 dayContent.append('<div class="ui message red changes-history-status">' + response.error + '</div>');
3552 } else if (response?.list) {
3553 if (response.list.length == 0) {
3554 let msg = MainWP.I18n.t('This plugin has no recorded activity in Dashboard Insights.');
3555 if ('theme' === type && '' === dt) {
3556 msg = MainWP.I18n.t('This theme has no recorded activity in Dashboard Insights.');
3557 } else if ('' !== dt) {
3558 if ('plugin' === type) {
3559 msg = MainWP.I18n.t('No history changes found for the plugin on this day.');
3560 } else {
3561 msg = MainWP.I18n.t('No history changes found for the theme on this day.');
3562 }
3563 }
3564 dayContent.append('<div class="ui message changes-history-status">' + msg + '</div>');
3565 } else {
3566 let content = '';
3567 let count_acts = 0;
3568 Object.entries(response.list).forEach(([idxslug, records]) => {
3569 const name = records[0].name;
3570 content += `<div class="ui accordion list-all-actions-in-day" data-slug="${records[0].item_slug}" data-name="${records[0].item_name}" data-siteid="${records[0].site_id}">
3571 <div class="title">
3572 <div class="ui container">
3573 <div class="ui grid">
3574 <div class="ten wide column middle aligned">
3575 <i class="dropdown icon"></i>
3576 ${name}
3577 </div>
3578 <div class="six wide column right aligned">
3579 <button type="button" class="ui circular blue mini button mainwp-list-history-switch-view">` + ('plugin' === type ? MainWP.I18n.t('Plugin History') : MainWP.I18n.t('Theme History')) + `</button> <button class="ui basic mini button ">${records.length} ` + MainWP.I18n.t('Actions') + `</button>
3580 </div>
3581 </div>
3582 </div>
3583 </div>
3584 <div class="content ui list">`;
3585 records.forEach(record => {
3586 content += `<div class="item" log-id="${record.details.log_id}">
3587 <div class="ui grid">
3588 <div class="eight wide column middle aligned">
3589 <i class="` + get_icon_history_event(record.details.action) + ` icon"></i>
3590 <span class="ui text ` + get_color_changes_event(record.details.action) + `">${record.details.event}</span> ` + MainWP.I18n.t('by') + ` <strong>${record.details.author_name}</strong> ` + MainWP.I18n.t('from') + `
3591 <strong>${record.details.source}</strong>
3592 </div>
3593 <div class="six wide column middle aligned">
3594 ` + (record.details?.old_version && record.details?.version ? record.details.old_version + '&rarr;' + record.details.version : '') + `
3595 </div>
3596 <div class="two wide column right aligned">
3597 ${record.details.at_hour}
3598 </div>
3599 </div>
3600 </div>`;
3601 count_acts++;
3602 });
3603 content += `</div>
3604 </div>`;
3605 });
3606
3607 if ('' !== content) {
3608 jQuery(md).find('.ui.header .main-text').text(his_date + ' ' + MainWP.I18n.t('History'));
3609 let accordWrapper = jQuery("<div>", {
3610 id: "change-history-according-wrapper",
3611 html: content
3612 });
3613 jQuery(md).find('.scrolling.content').html(accordWrapper);
3614 jQuery('#change-history-according-wrapper .ui.accordion').accordion({ exclusive: true });
3615
3616 jQuery('.mainwp-list-history-switch-view').off('click.accordionFix2').on('click.accordionFix2', function (e) {
3617 e.preventDefault();
3618 e.stopPropagation(); // now it runs before ancestor handlers
3619 listHistory_SwitchViewHandler(this);
3620 return false;
3621 });
3622 }
3623 }
3624 } else {
3625 dayContent.html('<div class="ui message red changes-history-status">' + MainWP.I18n.t('Undefined error occurred. Please try again.') + '</div>');
3626 }
3627 }, 'json');
3628
3629 return false;
3630 }
3631
3632
3633 let listHistory_SwitchViewHandler = function (btn) {
3634
3635 const parent = jQuery(btn).closest('.ui.accordion');
3636
3637 jQuery(btn).closest('.title').hasClass('active') || jQuery(btn).closest('.title').trigger('click');
3638
3639 jQuery(parent).find('.content.ui').html('<div class="ui active centered inline loader history-actions-loading"></div>');
3640
3641 let md = jQuery('#mainwp-plugin-theme-history-changes-modal');
3642 const type = jQuery(md).attr('history-type');
3643
3644 if ('theme' === type) {
3645 themeChangesLoadData.slug = jQuery(parent).data('slug');
3646 themeChangesLoadData.name = jQuery(parent).data('name');
3647 themeChangesLoadData.siteId = jQuery(parent).data('siteid');
3648 themeChangesLoadData.from_date = '';
3649 } else {
3650 pluginChangesLoadData.slug = jQuery(parent).data('slug');;
3651 pluginChangesLoadData.siteId = jQuery(parent).data('siteid');;
3652 pluginChangesLoadData.from_date = '';
3653 }
3654 mainwp_item_changes_load(btn);
3655 }
3656
3657
3658 /**
3659 * Install check plugins.
3660 *
3661 */
3662
3663 globalThis.mainwp_install_check_plugin_prepare = function (slug) {
3664 let selected = jQuery("input[name='install_checker[]']:checked");
3665 if (selected.length == 0) {
3666 feedback('mainwp-message-zone-install', MainWP.I18n.t('Please select website to install plugin.'), 'yellow');
3667 return;
3668 } else {
3669 selected.each(function () {
3670 jQuery(this).closest('.siteBulkInstall').attr('status', 'queue');
3671 });
3672 }
3673 jQuery('#mainwp-install-check-btn').addClass('disabled');
3674 mainwp_set_message_zone('#mainwp-message-zone-install', '<i class="notched circle loading icon"></i> ', false, true); // false: not change the color class.
3675 let data = mainwp_secure_data({
3676 action: 'mainwp_preparebulkinstallcheckplugin',
3677 slug: slug,
3678 });
3679 jQuery.post(ajaxurl, data, function (response) {
3680 mainwp_set_message_zone('#mainwp-message-zone-install');
3681 mainwp_install_check_plugin_start_next(response.url);
3682 }, 'json');
3683 };
3684
3685 let mainwp_install_check_plugin_start_next = function (url) {
3686 while ((siteToInstall = jQuery('.siteBulkInstall[status="queue"]:first')) && (siteToInstall.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR - modified outside the function.
3687 mainwp_install_check_plugin_start_specific(url, siteToInstall);
3688 }
3689 };
3690
3691 let mainwp_install_check_plugin_start_specific = function (url, siteToInstall) {
3692 bulkInstallCurrentThreads++;
3693
3694 siteToInstall.attr('status', 'progress');
3695 siteToInstall.find('.queue').hide();
3696 siteToInstall.find('.progress').show();
3697
3698 let data = mainwp_secure_data({
3699 action: 'mainwp_installbulkinstallplugintheme',
3700 type: 'plugin',
3701 url: url,
3702 activatePlugin: 'true',
3703 siteId: siteToInstall.attr('siteid')
3704 });
3705
3706 jQuery.post(ajaxurl, data, function (url, siteToInstall) {
3707 return function (response) {
3708 siteToInstall.attr('status', 'done');
3709 siteToInstall.find('.progress').hide();
3710
3711 let statusEl = siteToInstall.find('.status');
3712 statusEl.show();
3713
3714 if (response.error != undefined) {
3715 statusEl.html(response.error);
3716 statusEl.css('color', 'red');
3717 } else if (response?.ok[siteToInstall.attr('siteid')]) {
3718 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Installation completed successfully.') + '"><i class="check green icon"></i></span>');
3719 } else if (response?.errors[siteToInstall.attr('siteid')]) {
3720 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + response.errors[siteToInstall.attr('siteid')][1] + '"><i class="times red icon"></i></span>');
3721 } else {
3722 statusEl.html('<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Undefined error occurred. Please try again.') + '"><i class="times red icon"></i></span>');
3723 }
3724
3725 bulkInstallCurrentThreads--;
3726 bulkInstallDone++;
3727 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').progress('set progress', bulkInstallDone);
3728 jQuery('#plugintheme-installation-progress-modal .mainwp-modal-progress').find('.label').html(bulkInstallDone + '/' + mainwpVars.bulkInstallTotal + ' ' + MainWP.I18n.t('Installed'));
3729 mainwp_install_check_plugin_start_next(url);
3730 }
3731 }(url, siteToInstall), 'json');
3732 };
3733
3734 function isUrl(url) {
3735 try {
3736 new URL(url);
3737 return true;
3738 } catch (e) {
3739 console.log(e);
3740 }
3741 return false;
3742 }
3743
3744 function removeUrlParams(url, params) {
3745 try {
3746 const urlObj = new URL(url);
3747 jQuery(params).each(function (idx, param) {
3748 urlObj.searchParams.delete(param);
3749 });
3750 return urlObj.toString();
3751 } catch (e) {
3752 console.log(e);
3753 }
3754 return '';
3755 }
3756
3757 function setVisible(what, vis) {
3758 if (vis) {
3759 jQuery(what).show();
3760 } else {
3761 jQuery(what).hide();
3762 }
3763 }
3764
3765 const mainwp_scrollToElement = () => {
3766 jQuery('html,body').animate({
3767 scrollTop: 0
3768 }, 1000);
3769
3770 return false;
3771 }
3772
3773 function setHtml(what, text, ptag) {
3774 if (ptag === undefined)
3775 ptag = true;
3776
3777 setVisible(what, true);
3778 if (ptag)
3779 jQuery(what).html('<span>' + text + '</span>');
3780 else
3781 jQuery(what).html(text);
3782 mainwp_scrollToElement(); // to fix js conflict error from some other add-ons.
3783 }
3784
3785
3786 /**
3787 * Notes
3788 */
3789 jQuery(function () {
3790
3791 jQuery(document).on('click', '#mainwp-notes-cancel', function () {
3792 jQuery('#mainwp-notes-status').html('');
3793 jQuery('#mainwp-notes-status').removeClass('red green');
3794 mainwp_notes_hide();
3795 return false;
3796 });
3797
3798 jQuery(document).on('click', '#mainwp-notes-save', function () {
3799 let which = jQuery('#mainwp-which-note').val();
3800 if (which == 'site') {
3801 mainwp_notes_site_save();
3802 } else if (which == 'theme') {
3803 mainwp_notes_theme_save();
3804 } else if (which == 'plugin') {
3805 mainwp_notes_plugin_save();
3806 } else if (which == 'client') {
3807 mainwp_notes_client_save();
3808 }
3809 return false;
3810 });
3811
3812 jQuery(document).on('click', '.mainwp-edit-site-note', function () {
3813 let id = jQuery(this).attr('id').substring(13);
3814 let note = jQuery('#mainwp-notes-' + id + '-note').html();
3815 jQuery('#mainwp-notes-html').html(note == '' ? MainWP.I18n.t('No saved notes. Click the Edit button to edit site notes.') : note);
3816 jQuery('#mainwp-notes-note').val(note);
3817 jQuery('#mainwp-notes-websiteid').val(id);
3818 jQuery('#mainwp-which-note').val('site'); // to fix conflict.
3819 mainwp_notes_show();
3820 if (jQuery(this).attr('add-new')) {
3821 jQuery('#mainwp-notes-edit').trigger("click");
3822 }
3823 return false;
3824 });
3825
3826 jQuery(document).on('click', '#mainwp-notes-edit', function () {
3827 jQuery('#mainwp-notes-html').hide();
3828 jQuery('#mainwp-notes-editor').show();
3829 jQuery(this).hide();
3830 jQuery('#mainwp-notes-save').show();
3831 jQuery('#mainwp-notes-status').html('');
3832 jQuery('#mainwp-notes-status').removeClass('red green');
3833 return false;
3834 });
3835 jQuery('#redirectForm').trigger("submit");
3836 if (jQuery('div.ui.open-site-close-window').length > 0) {
3837 setTimeout(function () {
3838 globalThis.close()
3839 }, 3000);
3840 }
3841 });
3842
3843 globalThis.mainwp_notes_show = function (reloadClose) {
3844 if (reloadClose) {
3845 jQuery('#mainwp-notes-modal').modal({
3846 onHide: function () {
3847 mainwp_forceReload();
3848 }
3849 }).modal('show');
3850 } else {
3851 jQuery('#mainwp-notes-modal').modal({ closable: false }).modal('show');
3852 }
3853
3854 jQuery('#mainwp-notes-html').show();
3855 jQuery('#mainwp-notes-editor').hide();
3856 jQuery('#mainwp-notes-save').hide();
3857 jQuery('#mainwp-notes-edit').show();
3858 };
3859 let mainwp_notes_hide = function () {
3860 jQuery('#mainwp-notes-modal').modal('hide');
3861 };
3862 let mainwp_notes_site_save = function () {
3863 let normalid = jQuery('#mainwp-notes-websiteid').val();
3864 let newnote = jQuery('#mainwp-notes-note').val();
3865 newnote = newnote.replaceAll(/\r\n|\r|\n/g, '<br>');
3866 let data = mainwp_secure_data({
3867 action: 'mainwp_notes_save',
3868 websiteid: normalid,
3869 note: newnote
3870 });
3871
3872 jQuery('#mainwp-notes-status').html('<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Saving note. Please wait...')).show();
3873
3874 jQuery.post(ajaxurl, data, function (response) {
3875 if (response.error != undefined) {
3876 jQuery('#mainwp-notes-status').html(response.error).addClass('red');
3877 } else if (response.result == 'SUCCESS') {
3878 jQuery('#mainwp-notes-status').html(MainWP.I18n.t('Note saved successfully.')).addClass('green');
3879 if (jQuery('#mainwp-notes-' + normalid + '-note').length > 0) {
3880 jQuery('#mainwp-notes-' + normalid + '-note').html(response?.esc_note_content ?? '');
3881 jQuery('#mainwp-notes-html').html(response?.esc_note_content ?? '');
3882 }
3883 } else {
3884 jQuery('#mainwp-notes-status').html(MainWP.I18n.t('Undefined error occurred while saving your note!')).addClass('red');
3885 }
3886 }, 'json');
3887
3888 setTimeout(function () {
3889 jQuery('#mainwp-notes-status').fadeOut(300);
3890 }, 3000);
3891
3892 jQuery('#mainwp-notes-html').show();
3893 jQuery('#mainwp-notes-editor').hide();
3894 jQuery('#mainwp-notes-save').hide();
3895 jQuery('#mainwp-notes-edit').show();
3896
3897 };
3898
3899 globalThis.getErrorMessage = function (pError, msgOnly) { // NOSONAR - complex.
3900 if (pError.message == 'HTTPERROR') {
3901 return MainWP.I18n.t('HTTP error') + '! ' + pError.extra;
3902 } else if (pError.message == 'NOMAINWP' || pError == 'NOMAINWP') {
3903 return mainwp_js_get_error_not_detected_connect();
3904 } else if (pError.message == 'ERROR') {
3905 return 'ERROR' + ((pError.extra != '') && (pError.extra != undefined) ? ': ' + pError.extra : '');
3906 } else if (pError.message == 'WPERROR') {
3907 let extrMsg = (pError.extra != '') && (pError.extra != undefined) ? pError.extra : '';
3908 if (msgOnly != undefined && msgOnly && extrMsg != '') {
3909 return extrMsg;
3910 } else {
3911 return MainWP.I18n.t('ERROR on the child site') + ': ' + extrMsg;
3912 }
3913
3914 } else if (pError.message != undefined && pError.message != '') {
3915 return pError.message;
3916 } else {
3917 return pError;
3918 }
3919 };
3920
3921 globalThis.getErrorMessageInfo = function (repError, outputType) { // NOSONAR - complex.
3922 let msg = '';
3923 let msgUI = '<i class="red times icon"></i>';
3924
3925 if (repError.errorCode != undefined && repError.errorCode == 'SUSPENDED_SITE') {
3926 msg = MainWP.I18n.t('Suspended site.');
3927 msgUI = '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Suspended site.') + '"><i class="pause yellow icon"></i></span>';
3928 }
3929
3930 if (repError.errorCode != undefined && repError.errorCode == 'MAINWP_NOTICE') {
3931 if (repError.message != undefined) {
3932 msg = repError.message;
3933 msgUI = '<span data-inverted="" data-position="left center" data-tooltip="' + msg + '"><i class="pause circular yellow inverted icon"></i></span>';
3934 }
3935 }
3936
3937 if (msg == '') {
3938 msg = getErrorMessage(repError);
3939
3940 if (repError.message == 'NOMAINWP' || repError == 'NOMAINWP') {
3941 msg = mainwp_js_get_error_not_detected_connect();
3942 }
3943
3944 if (msg != '') {
3945 msgUI = '<span data-inverted="" data-position="left center" data-tooltip="' + msg + '"><i class="red times icon"></i></span>';
3946 }
3947 }
3948
3949 if (msg != '') {
3950 if (outputType != undefined && outputType == 'ui') {
3951 return msgUI;
3952 } else {
3953 return msg;
3954 }
3955 }
3956
3957 return repError;
3958 }
3959
3960 globalThis.dateToHMS = function (date) {
3961 if (mainwpParams?.time_format) {
3962 let time = moment(date);
3963 let format = mainwpParams['time_format'];
3964 format = format.replaceAll('g', 'h');
3965 format = format.replaceAll('i', 'mm');
3966 format = format.replaceAll('s', 'ss');
3967 format = format.replaceAll('F', 'MMMM');
3968 format = format.replaceAll('j', 'D');
3969 format = format.replaceAll('Y', 'YYYY');
3970 return time.format(format);
3971 }
3972 let h = date.getHours();
3973 let m = date.getMinutes();
3974 let s = date.getSeconds();
3975 return '' + (h <= 9 ? '0' + h : h) + ':' + (m <= 9 ? '0' + m : m) + ':' + (s <= 9 ? '0' + s : s);
3976 };
3977 globalThis.appendToDiv = function (pSelector, pText, pScrolldown, pShowTime) {
3978 if (pScrolldown == undefined)
3979 pScrolldown = true;
3980 if (pShowTime == undefined)
3981 pShowTime = true;
3982
3983 let theDiv = jQuery(pSelector);
3984 theDiv.append('<br />' + (pShowTime ? dateToHMS(new Date()) + ' ' : '') + pText);
3985 if (pScrolldown)
3986 theDiv.animate({ scrollTop: theDiv.prop("scrollHeight") }, 100);
3987 };
3988
3989 jQuery.fn.exists = function () {
3990 return (this.length !== 0);
3991 };
3992
3993
3994 globalThis.MainWP = globalThis.MainWP || {};
3995 globalThis.MainWP.I18n = globalThis.MainWP.I18n || {};
3996
3997 MainWP.I18n.t = function (text, ...args) {
3998 if (!text) {
3999 return text;
4000 }
4001
4002 // Replace non-alphanumeric characters (including Unicode/accented characters) with '_'
4003 const strippedText = text.replace(/[^\p{L}\p{N}_]/gu, '_');
4004
4005 let translated = text;
4006
4007 if (
4008 strippedText &&
4009 typeof mainwpTranslations !== 'undefined' &&
4010 mainwpTranslations[strippedText] !== undefined
4011 ) {
4012 translated = mainwpTranslations[strippedText];
4013 }
4014
4015 if (args.length === 0) {
4016 return translated;
4017 }
4018
4019 // Single-pass replacement to avoid placeholder collision issues
4020 return translated.replace(/%(\d+)/g, (match, index) => {
4021 const argIdx = parseInt(index, 10) - 1;
4022 return args[argIdx] !== undefined ? args[argIdx] : match;
4023 });
4024 };
4025
4026 // Deprecated. Remove in a future release.
4027 if (typeof globalThis.__ !== 'function') {
4028 globalThis.__ = function (text, ...args) {
4029 return globalThis.MainWP.I18n.t(text, ...args);
4030 };
4031 }
4032
4033 globalThis.mainwp_secure_data = function (data, includeDts) {
4034 if (data['action'] == undefined)
4035 return data;
4036
4037 if (security_nonces[data['action']] == undefined)
4038 return data;
4039
4040 data['security'] = security_nonces[data['action']];
4041 if (includeDts)
4042 data['dts'] = Math.round(Date.now() / 1000);
4043 return data;
4044 };
4045
4046
4047 globalThis.mainwp_uid = function () {
4048 // always start with a letter (for DOM friendlyness)
4049 let idstr = String.fromCodePoint(Math.floor((Math.random() * 25) + 65)); // NOSONAR - safe, it's id.
4050 do {
4051 // between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
4052 let ascicode = Math.floor((Math.random() * 42) + 48); // NOSONAR - safe, it's id.
4053 if (ascicode < 58 || ascicode > 64) {
4054 // exclude all chars between : (58) and @ (64)
4055 idstr += String.fromCodePoint(ascicode);
4056 }
4057 } while (idstr.length < 32);
4058
4059 return (idstr);
4060 };
4061
4062 globalThis.scrollToElement = function () {
4063 jQuery('html,body').animate({
4064 scrollTop: 0
4065 }, 1000);
4066
4067 return false;
4068 };
4069
4070 jQuery(function () {
4071 jQuery('#backup_filename').on('keypress', function (e) {
4072 let chr = String.fromCodePoint(e.which);
4073 return !"$^&*/".includes(chr);
4074 });
4075 jQuery('#backup_filename').on('change', function () {
4076 let value = jQuery(this).val();
4077 let notAllowed = ['$', '^', '&', '*', '/'];
4078 for (let char of notAllowed) {
4079 if (value.includes(char)) {
4080 value = value.replaceAll(char, '');
4081 jQuery(this).val(value);
4082 }
4083 }
4084 });
4085 });
4086
4087 /*
4088 * Server Info
4089 */
4090
4091 globalThis.serverinfo_prepare_download_info = function (communi) {
4092 let report = "";
4093 jQuery('.mainwp-system-info-table thead, .mainwp-system-info-table tbody').each(function () {
4094 let td_len = [35, 55, 45, 12, 12];
4095 let th_count = 0;
4096 let i;
4097 if (jQuery(this).is('thead')) {
4098 i = 0;
4099 report = report + "\n### ";
4100 th_count = jQuery(this).find('th:not(".mwp-not-generate-row")').length;
4101 jQuery(this).find('th:not(".mwp-not-generate-row")').each(function () {
4102 let len = td_len[i];
4103 if (i == 0 || i == th_count - 1)
4104 len = len - 4;
4105 report = report + jQuery.mwp_strCut(jQuery.mwp_get_serverinfo_export_text(jQuery(this), communi), len, ' ');
4106 i++;
4107 });
4108 report = report + " ###\n\n";
4109 } else {
4110 jQuery('tr', jQuery(this)).each(function () {
4111 if (communi && jQuery(this).hasClass('mwp-not-generate-row'))
4112 return;
4113 i = 0;
4114 jQuery(this).find('td:not(".mwp-not-generate-row")').each(function () {
4115 if (jQuery(this).hasClass('mwp-hide-generate-row')) {
4116 report = report + jQuery.mwp_strCut(' ', td_len[i], ' ');
4117 i++;
4118 return;
4119 }
4120 let outputText = jQuery.mwp_get_serverinfo_export_text(jQuery(this), communi);
4121 report = report + jQuery.mwp_strCut(outputText, td_len[i], ' ');
4122 i++;
4123 });
4124 report = report + "\n";
4125 });
4126
4127 }
4128 });
4129
4130 try {
4131 if (communi) {
4132 report = '```' + "\n" + report + "\n" + '```';
4133 }
4134 jQuery("#download-server-information textarea").val(report).trigger("select");
4135 } catch {
4136 console.log('Error:');
4137 }
4138 return false;
4139 }
4140
4141 jQuery.mwp_get_serverinfo_export_text = function (element, communi) {
4142 let cellExportText = element.attr('data-export-text');
4143 if (typeof cellExportText !== 'undefined' && cellExportText !== '') {
4144 return cellExportText.trim();
4145 }
4146
4147 let descendantExportElement = element.find('[data-export-text]').first();
4148 if (descendantExportElement.length > 0) {
4149 let descendantExportText = descendantExportElement.attr('data-export-text');
4150 if (typeof descendantExportText !== 'undefined' && descendantExportText !== '') {
4151 return descendantExportText.trim();
4152 }
4153 }
4154
4155 let communityValue = element.attr('data-community-value');
4156 if (communi && typeof communityValue !== 'undefined') {
4157 return communityValue;
4158 }
4159
4160 return element.text().trim();
4161 }
4162
4163 jQuery(document).on('click', '#mainwp-download-system-report', function () {
4164 serverinfo_prepare_download_info(false);
4165 let server_info = jQuery('#download-server-information textarea').val();
4166 let blob = new Blob([server_info], { type: "text/plain;charset=utf-8" });
4167 saveAs(blob, "mainwp-system-report.txt");
4168 return false;
4169 });
4170 jQuery(document).on('click', '#mainwp-download-community-system-report', function () {
4171 serverinfo_prepare_download_info(true);
4172 let server_info = jQuery('#download-server-information textarea').val();
4173 let blob = new Blob([server_info], { type: "text/plain;charset=utf-8" });
4174 saveAs(blob, "mainwp-community-system-report.txt");
4175 return false;
4176 });
4177
4178
4179 jQuery.mwp_strCut = function (i, l, s, w) {
4180 let o = i.toString();
4181 if (!s) {
4182 s = '0';
4183 }
4184 while (o.length < Number.parseInt(l)) {
4185 // empty
4186 if (w == 'undefined') {
4187 o = s + o;
4188 } else {
4189 o = o + s;
4190 }
4191 }
4192 return o;
4193 };
4194
4195 globalThis.updateExcludedFolders = function () {
4196 let excludedBackupFiles = jQuery('#excludedBackupFiles').html();
4197 jQuery('#mainwp-kbl-content').val(excludedBackupFiles == undefined ? '' : excludedBackupFiles);
4198
4199 let excludedCacheFiles = jQuery('#excludedCacheFiles').html();
4200 jQuery('#mainwp-kcl-content').val(excludedCacheFiles == undefined ? '' : excludedCacheFiles);
4201
4202 let excludedNonWPFiles = jQuery('#excludedNonWPFiles').html();
4203 jQuery('#mainwp-nwl-content').val(excludedNonWPFiles == undefined ? '' : excludedNonWPFiles);
4204 };
4205
4206
4207 jQuery(document).on('click', '.mainwp-events-notice-dismiss', function () {
4208 let notice = jQuery(this).attr('notice');
4209 jQuery(this).closest('.ui.message').fadeOut(500);
4210 let data = mainwp_secure_data({
4211 action: 'mainwp_events_notice_hide',
4212 notice: notice
4213 });
4214 jQuery.post(ajaxurl, data, function () {
4215 });
4216 return false;
4217 });
4218
4219 // Turn On child plugin auto update
4220 jQuery(document).on('click', '#mainwp_btn_autoupdate_and_trust', function () {
4221 jQuery(this).attr('disabled', 'true');
4222 let data = mainwp_secure_data({
4223 action: 'mainwp_autoupdate_and_trust_child'
4224 });
4225 jQuery.post(ajaxurl, data, function (res) {
4226 if (res == 'ok') {
4227 location.reload(true);
4228 } else {
4229 jQuery(this).prop("disabled", false);
4230 }
4231 });
4232 return false;
4233 });
4234
4235 // Hide installation warning
4236 jQuery(document).on('click', '#remove-mainwp-installation-warning', function () {
4237 jQuery(this).closest('.ui.message').fadeOut("slow");
4238 let data = mainwp_secure_data({
4239 action: 'mainwp_installation_warning_hide'
4240 });
4241 jQuery.post(ajaxurl, data, function () { });
4242 return false;
4243 });
4244
4245 jQuery(document).on('click', '.mainwp-notice-hide', function () {
4246 jQuery(this).closest('.ui.message').fadeOut("slow");
4247 return false;
4248 });
4249
4250 // Hide after installtion notices (PHP version, Trust MainWP Child, Multisite Warning and OpenSSL warning)
4251 jQuery(document).on('click', '.mainwp-notice-dismiss', function () {
4252 let notice_id = jQuery(this).attr('notice-id');
4253 let shortterm = jQuery(this).attr('shortterm-notice');
4254
4255 jQuery(this).closest('.ui.message').fadeOut("slow");
4256 let data = {
4257 action: 'mainwp_notice_status_update'
4258 };
4259 data['notice_id'] = notice_id;
4260 if(shortterm === '1'){
4261 data['short_term'] = 1;
4262 }
4263 jQuery.post(ajaxurl, mainwp_secure_data(data), function () { });
4264 return false;
4265 });
4266
4267
4268 globalThis.mainwp_notice_dismiss = function (notice_id, time_set) {
4269 let data = {
4270 action: 'mainwp_notice_status_update'
4271 };
4272 data['notice_id'] = notice_id;
4273 if (time_set !== undefined) {
4274 data['time_set'] = time_set ? 1 : 0;
4275 }
4276 jQuery.post(ajaxurl, mainwp_secure_data(data), function () {
4277 });
4278 return false;
4279 }
4280
4281
4282 jQuery(document).on('click', '.mainwp-activate-notice-dismiss', function () {
4283 jQuery(this).closest('tr').fadeOut("slow");
4284 let data = mainwp_secure_data({
4285 action: 'mainwp_dismiss_activate_notice',
4286 slug: jQuery(this).closest('tr').attr('slug')
4287 });
4288 jQuery.post(ajaxurl, data, function () {
4289 });
4290 return false;
4291 });
4292
4293 jQuery(document).on('click', '.mainwp-install-check-dismiss', function () {
4294 let notice_id = jQuery(this).attr('notice-id');
4295 jQuery(this).closest('.ui.message').fadeOut("slow");
4296 let data = {
4297 action: 'mainwp_notice_status_update'
4298 };
4299 data['notice_id'] = notice_id;
4300 jQuery.post(ajaxurl, mainwp_secure_data(data), function () { });
4301 return false;
4302 });
4303
4304 jQuery(document).on('click', '#mainwp-dismiss-sites-changes-actions-button', function () {
4305 mainwp_confirm('You are about to dismiss the selected changes?', function () {
4306 mainwp_delete_nonmainwp_data_start();
4307 });
4308 return false;
4309 });
4310
4311 let mainwp_managesites_update_childsite_value = function (siteId, uniqueId) {
4312 let data = mainwp_secure_data({
4313 action: 'mainwp_updatechildsite_value',
4314 site_id: siteId,
4315 unique_id: uniqueId
4316 });
4317 jQuery.post(ajaxurl, data, function () {
4318 });
4319 return false;
4320 };
4321
4322 jQuery(document).on('keyup', '#managegroups-filter', function () {
4323 let filter = jQuery(this).val();
4324 let groupItems = jQuery(this).parent().parent().find('li.managegroups-listitem');
4325 for (let igr of groupItems) {
4326 let currentElement = jQuery(igr);
4327 if (currentElement.hasClass('managegroups-group-add')) {
4328 continue;
4329 }
4330 let value = currentElement.find('span.text').text();
4331 if (value.includes(filter)) {
4332 currentElement.show();
4333 } else {
4334 currentElement.hide();
4335 }
4336 }
4337 });
4338
4339 // for normal checkboxes
4340 jQuery(document).on('change', '#cb-select-all-top, #cb-select-all-bottom', function () {
4341 let $this = jQuery(this), $table, controlChecked = $this.prop('checked');
4342
4343 $table = $this.closest('.dt-scroll').find('.dt-scroll-body table'); // for dt with scroll enabled.
4344
4345 // if no scrollable table.
4346 if ($table.length == 0) {
4347 $table = $this.closest('table.table.dataTable');
4348 }
4349
4350 if ($table.length == 0)
4351 return false;
4352
4353 $table.children('tbody').filter(':visible')
4354 .children().children('.check-column').find(':checkbox')
4355 .prop('checked', function () {
4356 if (jQuery(this).is(':hidden,:disabled')) {
4357 return false;
4358 }
4359 if (controlChecked) {
4360 jQuery(this).closest('tr').addClass('selected');
4361 return true;
4362 }
4363 jQuery(this).closest('tr').removeClass('selected');
4364 return false;
4365 });
4366
4367 $table.children('thead, tfoot').filter(':visible')
4368 .children().children('.check-column').find(':checkbox')
4369 .prop('checked', function () {
4370 if (controlChecked) {
4371 jQuery(this).closest('tr').addClass('selected');
4372 return true;
4373 }
4374 jQuery(this).closest('tr').removeClass('selected');
4375 return false;
4376 });
4377 let dtApi = jQuery($table).dataTable().api();
4378 let setStatus = controlChecked ? 'selected' : 'deselected';
4379 mainwp_datatable_fix_to_update_selected_rows_status(dtApi, setStatus);
4380 });
4381
4382
4383 jQuery(document).on('change', '.cb-select-all-parent-top, .cb-select-all-parent-bottom', function () {
4384
4385 let parentChecked = jQuery(this).is(":checked");
4386 let parentSelector = jQuery(this).attr('cb-parent-selector') ?? false;
4387
4388 if (false === parentSelector) {
4389 return;
4390 }
4391 jQuery(parentSelector + ' .ui.checkbox').find(':checkbox')
4392 .prop('checked', function () {
4393 if (parentChecked) {
4394 jQuery(this).closest('tr').addClass('selected');
4395 return true;
4396 }
4397 jQuery(this).closest('tr').removeClass('selected');
4398 return false;
4399 });
4400
4401 });
4402
4403 jQuery(function ($) {
4404 // Trigger the bulk actions
4405 $('#mainwp_sites_changes_bulk_dismiss_selected_btn').on('click', function () {
4406 if (jQuery('#mainwp-module-log-records-body-table tr').find('input[type="checkbox"]:checked').length == 0) {
4407 return;
4408 }
4409 let confirmMsg = MainWP.I18n.t("You are about to dismiss the selected changes?");
4410 mainwp_confirm(confirmMsg, function () { mainwp_sites_changes_actions_bulk_action('dismiss-selected'); });
4411 });
4412
4413 $('#mainwp_sites_changes_bulk_dismiss_all_btn').on('click', function () {
4414 let confirmMsg = MainWP.I18n.t("You are about to dismiss all changes?");
4415 mainwp_confirm(confirmMsg, function () { mainwp_sites_changes_actions_bulk_action('dismiss-all'); });
4416 });
4417
4418 // Trigger the bulk actions
4419 $('#mainwp_widget_sites_changes_bulk_dismiss_selected_btn').on('click', function () {
4420 if (jQuery('#mainwp-module-log-records-body-table tr').find('input[type="checkbox"]:checked').length == 0) {
4421 return;
4422 }
4423 let confirmMsg = MainWP.I18n.t("You are about to dismiss the selected changes?");
4424 mainwp_confirm(confirmMsg, function () { mainwp_sites_changes_actions_bulk_action('dismiss-selected', 'widget'); });
4425 });
4426
4427 $(document).on('click', '.insights-actions-row-dismiss', function () {
4428 return mainwp_insights_row_actions_dismiss(this);
4429 });
4430
4431 globalThis.mainwp_sites_changes_update_dismiss_button_state = function () {
4432 let checkedCount = jQuery('#mainwp-module-log-records-body-table tr').find('input[type="checkbox"]:checked').length;
4433 let totalRows = jQuery('#mainwp-module-log-records-body-table tr').not('.dt-empty').length;
4434
4435 if (checkedCount > 0) {
4436 jQuery('#mainwp_sites_changes_bulk_dismiss_selected_btn').removeClass('disabled');
4437 } else {
4438 jQuery('#mainwp_sites_changes_bulk_dismiss_selected_btn').addClass('disabled');
4439 }
4440
4441 if (totalRows > 0) {
4442 jQuery('#mainwp_sites_changes_bulk_dismiss_all_btn').removeClass('disabled');
4443 } else {
4444 jQuery('#mainwp_sites_changes_bulk_dismiss_all_btn').addClass('disabled');
4445 }
4446 }
4447
4448 jQuery(document).on('change', '#mainwp-module-log-records-body-table input[type="checkbox"]', function () {
4449 mainwp_sites_changes_update_dismiss_button_state();
4450 });
4451
4452 jQuery(document).on('change', '#cb-select-all-top, #cb-select-all-bottom', function () {
4453 mainwp_sites_changes_update_dismiss_button_state();
4454 });
4455 })
4456
4457 let mainwp_insights_row_actions_dismiss = function (obj) {
4458 let row = jQuery(obj).closest('tr');
4459 let confirmMsg = MainWP.I18n.t("You are about to dismiss the selected change?");
4460
4461 const renderMessage = (icon, message) => {
4462 row.html(
4463 '<td></td><td colspan="999"><i class="' +
4464 icon +
4465 ' icon"></i> ' +
4466 message +
4467 '</td>'
4468 );
4469 };
4470
4471 const updateDismissButtonState = () => {
4472 if (typeof mainwp_sites_changes_update_dismiss_button_state !== 'undefined') {
4473 mainwp_sites_changes_update_dismiss_button_state();
4474 }
4475 };
4476
4477 const fadeRow = () => {
4478 setTimeout(() => {
4479 jQuery(row).fadeOut('slow', updateDismissButtonState);
4480 }, 2000);
4481 };
4482
4483 let _callback = () => {
4484 row.html('<td></td><td colspan="999"><i class="notched circle loading icon"></i> Please wait...</td>');
4485 let data = mainwp_secure_data({
4486 action: 'mainwp_insight_events_dismiss_actions',
4487 log_id: jQuery(row).attr('log-id')
4488 });
4489 jQuery.post(ajaxurl, data, function (response) {
4490 if (response?.success !== 'yes') {
4491
4492 if (response?.error) {
4493 renderMessage('times red', response.error);
4494 } else {
4495 renderMessage('times red', 'The change could not be dismissed.');
4496 }
4497
4498 return;
4499 }
4500 renderMessage('green check', 'The change has been dismissed.');
4501 fadeRow();
4502 }, 'json');
4503 };
4504 mainwp_confirm(confirmMsg, _callback);
4505 return false;
4506 }
4507
4508
4509 // Manage Bulk Actions
4510 let mainwp_sites_changes_actions_bulk_action = function (act, which_act) {
4511 mainwpVars.bulkInstallTotal = 0;
4512 bulkInstallCurrentThreads = 0;
4513 bulkInstallDone = 0;
4514 mainwpVars.bulkActionIndent = '';
4515 if (which_act === 'widget') {
4516 mainwpVars.bulkActionIndent = 'widget';
4517 }
4518 if (act === 'dismiss-selected') {
4519 jQuery('#mainwp_sites_changes_bulk_dismiss_selected_btn').addClass('disabled');
4520 let selector = '#mainwp-module-log-records-body-table tr';
4521 mainwpVars.bulkInstallTotal = jQuery(selector).find('input[type="checkbox"]:checked').length;
4522 jQuery(selector).addClass('queue');
4523 if (jQuery(selector).length) {
4524 if (mainwpVars.bulkActionIndent === 'widget') {
4525 jQuery('#mainwp_widget_sites_changes_bulk_dismiss_selected_btn').addClass('disabled');
4526 } else {
4527 jQuery('#mainwp_sites_changes_bulk_dismiss_selected_btn').addClass('disabled');
4528 }
4529 }
4530 mainwp_sites_changes_actions_dismiss_start_next(selector);
4531 } else if (act === 'dismiss-all') {
4532 jQuery('#mainwp_sites_changes_bulk_dismiss_all_btn').addClass('disabled');
4533 mainwp_sites_changes_actions_dismiss_all();
4534 }
4535 }
4536
4537 let mainwp_sites_changes_actions_dismiss_start_next = function (selector) {
4538 while ((objProcess = jQuery(selector + '.queue:first')) && (objProcess.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR - modified outside the function.
4539 objProcess.removeClass('queue');
4540 if (objProcess.closest('tr').find('input[type="checkbox"]:checked').length == 0) {
4541 continue;
4542 }
4543 mainwp_sites_changes_actions_dismiss_specific(objProcess, selector);
4544 }
4545
4546 if (mainwpVars.bulkInstallTotal == bulkInstallDone) {
4547 if (mainwpVars.bulkActionIndent === 'widget') {
4548 jQuery('#mainwp_widget_sites_changes_bulk_dismiss_selected_btn').removeClass('disabled');
4549 } else {
4550 jQuery('#mainwp_sites_changes_bulk_dismiss_selected_btn').removeClass('disabled');
4551 }
4552 if (typeof mainwp_sites_changes_update_dismiss_button_state !== 'undefined') {
4553 mainwp_sites_changes_update_dismiss_button_state();
4554 }
4555 }
4556 }
4557
4558 let mainwp_sites_changes_actions_dismiss_specific = function (pObj, selector) {
4559 let row = pObj.closest('tr');
4560 let act_id = jQuery(row).attr('log-id');
4561
4562 bulkInstallCurrentThreads++;
4563
4564 let data = mainwp_secure_data({
4565 action: 'mainwp_insight_events_dismiss_actions',
4566 log_id: act_id
4567 });
4568
4569 row.html('<td></td><td colspan="999"><i class="notched circle loading icon"></i> Please wait...</td>');
4570
4571 jQuery.post(ajaxurl, data, function (response) {
4572 pObj.removeClass('queue');
4573 if (response) {
4574 if (response['error']) {
4575 row.html('<td></td><td colspan="999"><i class="times red icon"></i> ' + response['error'] + '</td>');
4576 } else if (response['success'] == 'yes') {
4577 row.html('<td></td><td colspan="999"><i class="green check icon"></i> The change has been dismissed.</td>');
4578 setTimeout(function () {
4579 jQuery(row).fadeOut("slow");
4580 }, 2000);
4581 } else {
4582 row.html('<td></td><td colspan="999"><i class="times red icon"></i> Failed. Please try again.</td>');
4583 }
4584 } else {
4585 row.html('<td></td><td colspan="999"><i class="times red icon"></i> Failed. Please try again.</td>');
4586 }
4587
4588 bulkInstallCurrentThreads--;
4589 bulkInstallDone++;
4590 mainwp_sites_changes_actions_dismiss_start_next(selector);
4591 }, 'json');
4592 return false;
4593 }
4594
4595 let mainwp_sites_changes_actions_dismiss_all = function () {
4596 let data = mainwp_secure_data({
4597 action: 'mainwp_insight_events_dismiss_all',
4598 });
4599 mainwp_showhide_message('mainwp-message-zone-top', '<i class="notched circle loading icon"></i> Please wait...', '');
4600 jQuery.post(ajaxurl, data, function (response) {
4601 if (response) {
4602 if (response['error']) {
4603 mainwp_showhide_message('mainwp-message-zone-top', response['error'], 'red');
4604 } else if (response['success'] == 'yes') {
4605 mainwp_showhide_message('mainwp-message-zone-top', 'All changes have been dismissed.', 'green');
4606 setTimeout(function () {
4607 mainwp_forceReload();
4608 }, 2000);
4609 } else {
4610 mainwp_showhide_message('mainwp-message-zone-top', 'Failed. Please try again.', 'red');
4611 }
4612 } else {
4613 mainwp_showhide_message('mainwp-message-zone-top', 'Failed. Please try again.', 'red');
4614 }
4615 }, 'json');
4616 return false;
4617
4618 }
4619
4620
4621 globalThis.mainwp_datatable_fix_to_update_selected_rows_status = function (dtApi, setStatus) {
4622 if (dtApi) {
4623 if ('selected' === setStatus) {
4624 dtApi.rows('.selected').select(); // update selected status.
4625 } else if ('deselected' === setStatus) {
4626 dtApi.rows().deselect(); // update deselected status.
4627 }
4628 }
4629 }
4630
4631 globalThis.mainwp_datatable_fix_to_update_rows_state = function (tblSelect) {
4632 if (jQuery(tblSelect).length) {
4633 let $table = jQuery(tblSelect);
4634
4635 let dtApi = jQuery($table).dataTable().api(); // NOTE: not use DataTable().
4636
4637 mainwp_datatable_fix_to_update_selected_rows_status(dtApi, 'deselected'); // clear saved state.
4638
4639 $table.children('tbody').filter(':visible').find('tr').each(function () {
4640 if (jQuery(this).children('.check-column').find(':checkbox').is(':checked')) {
4641 jQuery(this).addClass('selected');
4642 } else if (jQuery(this).hasClass('selected')) {
4643 jQuery(this).removeClass('selected');
4644 }
4645 });
4646
4647 mainwp_datatable_fix_to_update_selected_rows_status(dtApi, 'selected'); // to update selected state.
4648 }
4649 }
4650
4651 globalThis.mainwp_datatable_fix_reorder_selected_rows_status = function () {
4652 jQuery('.table.dataTable tbody').filter(':visible').children('tr.selected').find(':checkbox').prop('checked', true);
4653 };
4654
4655 // fix menu overflow with scroll tables.
4656 globalThis.mainwp_datatable_fix_menu_overflow = function (pTableSelector, pTop, pRight) {
4657 if (pTableSelector === undefined) {
4658 console.warn('mainwp_datatable_fix_menu_overflow: requires params - $pTableSelector');
4659 }
4660 let dtScrollBdCls = '.dt-scroll-body';
4661 let dtScrollCls = '.dt-scroll';
4662 let fix_overflow = jQuery('.mainwp-content-wrap').attr('menu-overflow');
4663 jQuery(document).on('click', 'table td.check-column.dtr-control', function () {
4664 if (jQuery(this).parent().hasClass('parent')) {
4665 let chilRow = jQuery(this).parent().next();
4666 jQuery(chilRow).find('.ui.dropdown').dropdown();
4667 mainwp_datatable_fix_child_menu_overflow(chilRow, fix_overflow);
4668 }
4669 });
4670 let tblSelect = pTableSelector ?? 'table';
4671
4672 // to prevent double events.
4673 jQuery(tblSelect + ' tr td .ui.right.pointing.dropdown').each(function () {
4674 let parentTB = jQuery(this).closest('table');
4675 if (parentTB.attr('fixed-menu-overflow') === undefined) {
4676 parentTB.attr('fixed-menu-overflow', 'no'); // to init click menu events.
4677 }
4678 });
4679
4680 jQuery(tblSelect + ' tr td .ui.left.pointing.dropdown').each(function () {
4681 let parentTB = jQuery(this).closest('table');
4682 if (parentTB.attr('fixed-menu-overflow') === undefined) {
4683 parentTB.attr('fixed-menu-overflow', 'no'); // to init click menu events.
4684 }
4685 });
4686
4687 // if table selector specific.
4688 if (pTableSelector !== undefined) {
4689 if (jQuery(pTableSelector + '[fixed-menu-overflow="yes"]').length) {
4690 jQuery(pTableSelector + '[fixed-menu-overflow="yes"]').attr('fixed-menu-overflow', 'no'); // to init menus events click.
4691 }
4692 }
4693
4694
4695 // Fix the overflow prbolem for the actions menu element (right pointing menu).
4696 jQuery(tblSelect + '[fixed-menu-overflow="no"] tr td .ui.right.pointing.dropdown').on('click', function () {
4697 jQuery(this).closest(dtScrollBdCls).css('position', '');
4698 jQuery(this).closest(dtScrollCls).css('position', 'relative');
4699 jQuery(this).css('position', 'static');
4700 let fix_overflow = jQuery('.mainwp-content-wrap').attr('menu-overflow');
4701 let position = jQuery(this).position();
4702 let top = position.top;
4703 let right = 50;
4704 if (fix_overflow > 1) {
4705 position = jQuery(this).closest('td').position();
4706 top = position.top + 85; //85
4707 }
4708
4709 if (pTop !== undefined) {
4710 top = top + pTop;
4711 }
4712 if (pRight !== undefined) {
4713 right = right + pRight;
4714 }
4715
4716 jQuery(this).find('.menu').css('min-width', '170px');
4717 jQuery(this).find('.menu').css('top', top);
4718 jQuery(this).find('.menu')[0].style.setProperty('right', right + 'px', 'important');
4719 });
4720
4721 // Fix the overflow prbolem for the actions menu element (left pointing menu).
4722 jQuery(tblSelect + '[fixed-menu-overflow="no"] tr td .ui.left.pointing.dropdown').on('click', function () {
4723 jQuery(this).closest(dtScrollBdCls).css('position', '');
4724 jQuery(this).closest(dtScrollCls).css('position', 'relative');
4725 jQuery(this).css('position', 'static');
4726 let position = jQuery(this).position();
4727
4728 let top = position.top;
4729 let left = position.left - 159;
4730
4731 if (fix_overflow > 1) {
4732 position = jQuery(this).closest('td').position();
4733 let scroll_left = jQuery(this).closest(dtScrollBdCls).scrollLeft();
4734 top = position.top + 85;
4735 left = position.left - scroll_left - 145;
4736 }
4737
4738 if (pTop !== undefined) {
4739 top = top + pTop;
4740 }
4741
4742 jQuery(this).find('.menu').css('min-width', '150px');
4743 jQuery(this).removeClass('left');
4744 jQuery(this).addClass('right');
4745 jQuery(this).find('.menu').css('top', top);
4746 jQuery(this).find('.menu')[0].style.setProperty('left', left + 'px', 'important');
4747 });
4748
4749 jQuery(tblSelect + '[fixed-menu-overflow="no"]').each(function () {
4750 jQuery(this).attr('fixed-menu-overflow', 'yes');
4751 });
4752
4753 mainwp_datatable_fix_reorder_selected_rows_status();
4754 }
4755
4756
4757 let mainwp_datatable_fix_child_menu_overflow = function (chilRow, fix_overflow) {
4758 let dtScrollBdCls = '.dt-scroll-body';
4759 let dtScrollCls = '.dt-scroll';
4760 // Fix the overflow prbolem for the actions child menu element (pointing menu).
4761 jQuery(chilRow).find('.ui.pointing.dropdown').on('click', function () {
4762
4763 let position = jQuery(this).position();
4764 let left = position.left + 30;
4765 let top = position.top;
4766
4767 if (fix_overflow > 1) {
4768 position = jQuery(this).closest('td.child').position();
4769 top = position.top + jQuery(this).closest('td.child').height() + 85;
4770 }
4771
4772 jQuery(this).closest(dtScrollBdCls).css('position', '');
4773 jQuery(this).closest(dtScrollCls).css('position', 'relative');
4774 jQuery(this).css('position', 'static');
4775 jQuery(this).find('.menu').css('top', top);
4776 jQuery(this).find('.menu').css('left', left);
4777 jQuery(this).find('.menu').css('min-width', '170px');
4778 });
4779 }
4780
4781
4782 globalThis.mainwp_responsive_fix_remove_child_row = function (el) {
4783 if (jQuery(el).hasClass('dt-hasChild')) { // to fix.
4784 jQuery(el).next().remove();
4785 }
4786 }
4787
4788 /* eslint-disable complexity */
4789 function mainwp_according_table_sorting(pObj) { // NOSONAR - complex.
4790 let table, th, rows, switching, i, x, y, xVal, yVal, campare = false, shouldSwitch = false, dir, switchcount = 0, n, skip = 1;
4791 table = jQuery(pObj).closest('table')[0];
4792 let subline_skip = 2;
4793 if ('mainwp-wordpress-updates-table' == jQuery(table).attr('id')) {
4794 subline_skip = 1; // for rows without subline.
4795 skip = 0;
4796 }
4797
4798 // get TH element
4799 if (jQuery(pObj)[0].tagName == 'TH') {
4800 th = jQuery(pObj)[0];
4801 } else {
4802 th = jQuery(pObj).closest('th')[0];
4803 }
4804
4805 n = th.cellIndex;
4806 switching = true;
4807
4808 // check header and footer of according table
4809 if (jQuery(table).children('thead,tfoot').length > 0)
4810 skip += jQuery(table).children('thead,tfoot').length; // skip sorting header, footer
4811
4812 dir = "asc";
4813 /* loop until switching has been done: */
4814 while (switching) {
4815 switching = false;
4816 rows = table.rows;
4817 /* Loop through all table rows */
4818 for (i = 1; i < (rows.length - skip); i += subline_skip) { // skip content according rows, sort by title rows only
4819 shouldSwitch = false;
4820 /* Get the two elements you want to compare,
4821 one from current row and one from the next-next: */
4822 x = rows[i].getElementsByTagName("TD")[n];
4823 y = rows[i + subline_skip].getElementsByTagName("TD")[n];
4824
4825 // if sort value attribute existed then sorting on that else sorting on cell value
4826 if (x.hasAttribute('sort-value')) {
4827 xVal = Number.parseInt(x.getAttribute('sort-value'));
4828 yVal = Number.parseInt(y.getAttribute('sort-value'));
4829 let tmp = xVal > yVal ? -1 : 1;
4830 campare = (xVal == yVal) ? 0 : tmp;
4831 } else {
4832 // to prevent text() clear text content
4833 xVal = '<p>' + x.innerHTML + '</p>';
4834 yVal = '<p>' + y.innerHTML + '</p>';
4835 xVal = jQuery(xVal).text().trim().toLowerCase();
4836 yVal = jQuery(yVal).text().trim().toLowerCase();
4837 campare = yVal.localeCompare(xVal);
4838 }
4839
4840 /* Check if the two rows should switch place */
4841 if (dir == "asc") {
4842 if (campare < 0) { //xVal > yVal
4843 shouldSwitch = true;
4844 // break the loop:
4845 break;
4846 }
4847 } else if (dir == "desc") {
4848 if (campare > 0) { //xVal < yVal
4849 // break the loop:
4850 shouldSwitch = true;
4851 break;
4852 }
4853 }
4854 }
4855 if (shouldSwitch) {
4856 if (2 == subline_skip) {
4857 rows[i].parentNode.insertBefore(rows[i + 2], rows[i]);
4858 rows[i + 1].parentNode.insertBefore(rows[i + 3], rows[i + 1]);
4859 } else {
4860 rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); // switch 2 rows.
4861 }
4862 switching = true;
4863 // increase this count by 1, that is ok
4864 switchcount++;
4865 } else if (switchcount == 0 && dir == "asc") {
4866 /* If no switching has been done AND the direction is "asc",
4867 set the direction to "desc" and run the while loop again. */
4868 dir = "desc";
4869 switching = true;
4870 }
4871 }
4872
4873 // no row sorting so change direction for arrows switch
4874 if (switchcount == 0) {
4875 if (jQuery(pObj).hasClass('ascending')) {
4876 dir = "desc";
4877 } else {
4878 dir = "asc";
4879 }
4880 }
4881
4882 // add/remove class for arrows displaying
4883 if (dir == "asc") {
4884 jQuery(pObj).addClass('ascending');
4885 jQuery(pObj).removeClass('descending');
4886 } else {
4887 jQuery(pObj).removeClass('ascending');
4888 jQuery(pObj).addClass('descending');
4889 }
4890 }
4891 /* eslint-enable complexity */
4892
4893 jQuery(function () {
4894 jQuery('.handle-accordion-sorting').on('click', function () {
4895 mainwp_according_table_sorting(this);
4896 return false;
4897 });
4898 });
4899
4900 // Force Dashboard to reestablish connection by destroying sessions - Part 1
4901 let mainwp_force_destroy_sessions = function () {
4902 let confirmMsg = MainWP.I18n.t('Are you sure you want to force your MainWP Dashboard to reconnect with your child sites?');
4903 mainwp_confirm(confirmMsg, function () {
4904 mainwp_force_destroy_sessions_websites = jQuery('.dashboard_wp_id[error-status=0]').map(function (indx, el) {
4905 return jQuery(el).val();
4906 });
4907 mainwpPopup('#mainwp-sync-sites-modal').setTitle(MainWP.I18n.t('Re-establish Connection')); // popup displayed.
4908 mainwpPopup('#mainwp-sync-sites-modal').init({ progressMax: mainwp_force_destroy_sessions_websites.length });
4909 mainwp_force_destroy_sessions_part_2(0);
4910 });
4911 };
4912
4913 let mainwp_force_destroy_sessions_part_2 = function (id) {
4914 if (id >= mainwp_force_destroy_sessions_websites.length) {
4915 mainwp_force_destroy_sessions_websites = [];
4916 if (mainwp_force_destroy_sessions_successed == mainwp_force_destroy_sessions_websites.length) {
4917 setTimeout(function () {
4918 mainwpPopup('#mainwp-sync-sites-modal').close(true);
4919 }, 3000);
4920 }
4921 mainwpPopup('#mainwp-sync-sites-modal').close(true);
4922 return;
4923 }
4924
4925 let website_id = mainwp_force_destroy_sessions_websites[id];
4926 dashboard_update_site_status(website_id, '<i class="sync alternate loading icon"></i>');
4927
4928 jQuery.post(ajaxurl, { 'action': 'mainwp_force_destroy_sessions', 'website_id': website_id, 'security': security_nonces['mainwp_force_destroy_sessions'] }, function (response) {
4929 let counter = id + 1;
4930 mainwp_force_destroy_sessions_part_2(counter);
4931
4932 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(counter);
4933
4934 if ('error' in response) {
4935 dashboard_update_site_status(website_id, '<i class="exclamation red icon"></i>');
4936 } else if ('success' in response) {
4937 mainwp_force_destroy_sessions_successed += 1;
4938 dashboard_update_site_status(website_id, '<i class="check green icon"></i>', true);
4939 } else {
4940 dashboard_update_site_status(website_id, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process timed out. Please try again.') + '">');
4941 }
4942 }, 'json').fail(function () {
4943 let counter = id + 1;
4944 mainwp_force_destroy_sessions_part_2(counter);
4945 mainwpPopup('#mainwp-sync-sites-modal').setProgressSite(counter);
4946
4947 dashboard_update_site_status(website_id, '<i class="exclamation red icon"></i>');
4948 });
4949
4950 };
4951
4952 let mainwp_force_destroy_sessions_successed = 0;
4953 let mainwp_force_destroy_sessions_websites = [];
4954
4955
4956 jQuery(document).on('change', '#mainwp_archiveFormat', function () {
4957 let zipMethod = jQuery(this).val();
4958 zipMethod = zipMethod.replaceAll('.', '\\.'); // NOSONAR - escape is correct.
4959 jQuery('span.archive_info').hide();
4960 jQuery('span#info_' + zipMethod).show();
4961
4962 jQuery('tr.archive_method').hide();
4963 jQuery('tr.archive_' + zipMethod).show();
4964
4965 // compare new layout
4966 jQuery('div.archive_method').hide();
4967 jQuery('div.archive_' + zipMethod).show();
4968 });
4969
4970 let mainwp_import_demo_data_action = function (obj) {
4971 let confirmation = "Are you sure you want to import demo content into your MainWP Dashboard?";
4972 let msg_import = (jQuery(obj).attr('page-import') == 'qsw-import') ? '&message=qsw-import' : '';
4973 mainwp_confirm(confirmation, function () {
4974 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Importing. Please wait...'), '');
4975 let data = mainwp_secure_data({
4976 action: 'mainwp_import_demo_data',
4977 });
4978
4979 jQuery.post(ajaxurl, data, function (response) {
4980 let error = false;
4981 if (response.count === undefined) {
4982 error = true;
4983 feedback('mainwp-message-zone', MainWP.I18n.t('Undefined error. Please try again.'), 'green');
4984 } else {
4985 feedback('mainwp-message-zone', MainWP.I18n.t('The demo content has been imported into your MainWP Dashboard.'), 'green');
4986 }
4987
4988 if (!error) {
4989 setTimeout(function () {
4990 mainwp_forceReload('admin.php?page=mainwp_tab' + msg_import);
4991 }, 3000);
4992 }
4993 }, 'json');
4994 });
4995 }
4996
4997 let mainwp_remove_demo_data_action = function () {
4998 let confirmation = "Are you sure you want to delete demo content from your MainWP Dashboard?";
4999 mainwp_confirm(confirmation, function () {
5000 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Deleting. Please wait...'), '');
5001 let data = mainwp_secure_data({
5002 action: 'mainwp_delete_demo_data',
5003 });
5004 jQuery.post(ajaxurl, data, function (response) {
5005 let error = false;
5006 if (response.success === undefined) {
5007 error = true;
5008 feedback('mainwp-message-zone', MainWP.I18n.t('Undefined error. Please try again.'), 'green');
5009 } else {
5010 feedback('mainwp-message-zone', MainWP.I18n.t('The demo content has been deleted from your MainWP Dashboard.'), 'green');
5011 }
5012
5013 if (!error) {
5014 setTimeout(function () {
5015 mainwp_forceReload('admin.php?page=mainwp-setup');
5016 }, 3000);
5017 }
5018
5019 }, 'json');
5020 });
5021 }
5022
5023 // MainWP Tools
5024 jQuery(function () {
5025 jQuery(document).on('click', '#force-destroy-sessions-button', function () {
5026 mainwp_force_destroy_sessions();
5027 });
5028
5029 jQuery(document).on('click', '.mainwp-import-demo-data-button', function (event) {
5030 mainwp_import_demo_data_action(this);
5031 event.preventDefault();
5032 });
5033
5034 jQuery(document).on('click', '.mainwp-remove-demo-data-button', function () {
5035 mainwp_remove_demo_data_action();
5036 return false; //required this return.
5037 });
5038 });
5039
5040
5041 let mainwp_tool_renew_connections_show = function () {
5042 jQuery('#mainwp-tool-renew-connect-modal').modal({
5043 allowMultiple: true,
5044 closable: false,
5045 onHide: function () {
5046 mainwp_forceReload('admin.php?page=MainWPTools');
5047 },
5048 onShow: function () {
5049 if (jQuery('#mainwp-tool-renew-connect-modal .mainwp_selected_sites_item.item.warning').length == 0) {
5050 jQuery('#mainwp-tool-renew-connect-modal .mainwp-ss-select-disconnected').hide();
5051 jQuery('#mainwp-tool-renew-connect-modal .mainwp-ss-deselect-disconnected').hide();
5052 }
5053 }
5054 }).modal('show');
5055 };
5056
5057 let mainwp_tool_prepare_renew_connections = function (objBtn) {
5058
5059 let errors = [];
5060 let selected_sites = [];
5061 mainwp_set_message_zone('#mainwp-message-zone-modal');
5062
5063 jQuery("input[name='selected_sites[]']:checked").each(function () {
5064 selected_sites.push(jQuery(this).val());
5065 });
5066 if (selected_sites.length == 0) {
5067 errors.push(MainWP.I18n.t('Please select at least one website to start.'));
5068 }
5069
5070 if (errors.length > 0) {
5071 mainwp_set_message_zone('#mainwp-message-zone-modal', errors.join('<br />'), 'yellow');
5072 return;
5073 } else {
5074 mainwp_set_message_zone('#mainwp-message-zone-modal');
5075 }
5076
5077 let confirmation = MainWP.I18n.t("This process will create a new OpenSSL Key Pair on your MainWP Dashboard and Set the new Public Key to your Child site(s). Are you sure you want to proceed?");
5078
5079 mainwp_confirm(confirmation, function () {
5080 jQuery(objBtn).attr('disabled', true);
5081
5082 jQuery('#mainwp-tool-renew-connect-modal .mainwp-select-sites-wrapper').hide();
5083
5084 let statusEl = jQuery('#mainwp-message-zone-modal');
5085 statusEl.html('<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Please wait...'));
5086 statusEl.show();
5087
5088 let data = mainwp_secure_data({
5089 action: 'mainwp_prepare_renew_connections',
5090 'sites[]': selected_sites,
5091 });
5092
5093 jQuery.post(ajaxurl, data, function (response) {
5094 let undefError = false;
5095 if (response) {
5096 if (response.result != '') {
5097 jQuery('#mainwp-tool-renew-connect-modal').find('#mainwp-renew-connections-list').html(response.result);
5098 mainwpVars.bulkInstallTotal = jQuery('#mainwp-renew-connections-list .item').length;
5099 jQuery('#mainwp-tool-renew-connect-modal .mainwp-modal-progress').show();
5100 jQuery('#mainwp-tool-renew-connect-modal .mainwp-modal-progress').progress({ value: 0, total: mainwpVars.bulkInstallTotal });
5101 mainwp_tool_renew_connections_start_next();
5102 statusEl.hide();
5103 } else if (response.error) {
5104 statusEl.addClass('red');
5105 statusEl.html(response.error).fadeIn();
5106 } else {
5107 undefError = true;
5108 }
5109 } else {
5110 undefError = true;
5111 }
5112
5113 if (undefError) {
5114 statusEl.addClass('red');
5115 statusEl.html(MainWP.I18n.t('Undefined error occurred. Please try again.')).fadeIn();
5116 }
5117 }, 'json');
5118 }, false, false, true);
5119 }
5120
5121 let connection_renew_status = function (siteId, newStatus) {
5122 jQuery('#mainwp-renew-connections-list .renew-site-status[siteid="' + siteId + '"]').html(newStatus);
5123 };
5124
5125 let mainwp_tool_renew_connections_start_next = function () {
5126 while ((siteToReNew = jQuery('#mainwp-renew-connections-list .item[status="queue"]:first')) && (siteToReNew.length > 0) && (bulkInstallCurrentThreads < bulkInstallMaxThreads)) { // NOSONAR - modified outside the function.
5127 mainwp_tool_renew_connections_start_specific(siteToReNew);
5128 }
5129 }
5130
5131 let mainwp_tool_renew_connections_start_specific = function (siteItem) {
5132
5133 bulkInstallCurrentThreads++;
5134
5135 siteItem.attr('status', 'progress');
5136 let siteId = siteItem.find('.renew-site-status').attr('siteid');
5137
5138 let data = mainwp_secure_data({
5139 action: 'mainwp_renew_connections',
5140 siteid: siteId
5141 });
5142
5143 connection_renew_status(siteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Processing...') + '"><i class="sync alternate loading icon"></i></span>');
5144 jQuery.post(ajaxurl, data, function (response) {
5145 if (response.error) {
5146 connection_renew_status(siteId, '<span data-inverted="" data-position="left center" data-tooltip="' + response.error + '"><i class="times red icon"></i></span>');
5147 } else if (response.result == 'success') {
5148 connection_renew_status(siteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Renew connnection process completed successfully.') + '"><i class="check green icon"></i></span>');
5149 } else {
5150 connection_renew_status(siteId, '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Undefined error.') + '"><i class="times red icon"></i></span>');
5151
5152 }
5153 bulkInstallCurrentThreads--;
5154 bulkInstallDone++;
5155 jQuery('#mainwp-tool-renew-connect-modal .mainwp-modal-progress').progress('set progress', bulkInstallDone);
5156 jQuery('#mainwp-tool-renew-connect-modal .mainwp-modal-progress').find('.label').html(bulkInstallDone + '/' + mainwpVars.bulkInstallTotal + ' ' + MainWP.I18n.t('Processed'));
5157 mainwp_tool_renew_connections_start_next();
5158 }, 'json');
5159 }
5160
5161
5162 jQuery(function () {
5163 if (jQuery('body.mainwp-ui').length > 0) {
5164 jQuery('.mainwp-ui-page .ui.dropdown:not(.not-auto-init)').dropdown();
5165 jQuery('.mainwp-ui-page .ui.checkbox:not(.not-auto-init)').checkbox();
5166 jQuery('.mainwp-ui-page .ui.dropdown').filter('[init-value]').each(function () {
5167 let values = jQuery(this).attr('init-value').split(',');
5168 jQuery(this).dropdown('set selected', values);
5169 });
5170 }
5171 });
5172
5173 // MainWP Action Logs
5174 jQuery(document).on('click', '.mainwp-action-log-show-more', function () {
5175 let content = jQuery(this).closest('.item').find('.mainwp-action-log-site-response').text();
5176 jQuery('#mainwp-action-log-response-modal').modal({
5177 closable: false,
5178 onHide: function () {
5179 location.reload();
5180 }
5181 }).modal('show');
5182 jQuery('#mainwp-action-log-response-modal .content-response').text(content);
5183 });
5184
5185 // MainWP Show Response
5186 jQuery(document).on('click', '.mainwp-show-response', function () {
5187 let content = jQuery('#mainwp-response-data-container').attr('resp-data');
5188 jQuery('#mainwp-response-data-modal').modal({
5189 closable: false,
5190 onHide: function () {
5191 jQuery('#mainwp-response-data-modal .content-response').text('');
5192 }
5193 }).modal('show');
5194 jQuery('#mainwp-response-data-modal .content-response').text(content);
5195 });
5196
5197 // Copy to clipboard for response modals.
5198 jQuery(document).on('click', '.mainwp-response-copy-button', function (event) {
5199 let modal = jQuery(this).closest('.ui.modal');
5200 let data = jQuery(modal).find('.content.content-response').text();
5201 let $temp_txtarea = jQuery('<textarea style="opacity:0">');
5202 jQuery('body').append($temp_txtarea);
5203 $temp_txtarea.val(data).trigger("select"); // to support 'copy' method.
5204 mainwp_copy_to_clipboard(data, event);
5205 $temp_txtarea.remove();
5206 return false;
5207 });
5208
5209 jQuery(function () {
5210 if (typeof postboxes !== "undefined" && typeof mainwp_postbox_page !== "undefined") {
5211 postboxes.add_postbox_toggles(mainwp_postbox_page);
5212 }
5213 mainwp_setCookie();
5214 mainwp_getCookie();
5215 });
5216
5217 jQuery(document).on('click', '.close.icon', function () {
5218 jQuery(this).parent().hide();
5219 });
5220
5221 /*
5222 * to compatible
5223 */
5224 function mainwp_setCookie() {
5225 return false;
5226 }
5227
5228 function mainwp_getCookie() {
5229 return false;
5230 }
5231
5232 let mainwp_setttings_fields_indicator_show = function (specific_header_indicator) {
5233 if (specific_header_indicator !== undefined) {
5234 mainwp_setttings_fields_indicator_specific_show(specific_header_indicator);
5235 return;
5236 }
5237 // for each header indicator.
5238 jQuery('.settings-field-header-indicator').each(function () {
5239 mainwp_setttings_fields_indicator_specific_show(this);
5240 });
5241 }
5242
5243 let mainwp_setttings_fields_indicator_specific_show = function (obj) {
5244 let cls = jQuery(obj).attr('field-indicator-wrapper-class');
5245 if ('' != cls && jQuery('.' + cls + ' .settings-field-icon-indicator.visible-indicator').length > 0) {
5246 jQuery(this).attr('style', 'display:inline-block;');
5247 jQuery(this).addClass('visible-indicator');
5248 }
5249 }
5250
5251
5252 jQuery(function ($) {
5253 if (jQuery('.mainwp-ui-page').length) {
5254 mainwp_setttings_fields_indicator_show();
5255 }
5256
5257 jQuery(document).on('input', '.settings-field-value-change-handler', function () {
5258 let val = $(this).val();
5259 mainwp_settings_fields_value_on_change(this, val);
5260 });
5261
5262 jQuery(document).on('change', '.settings-field-value-change-handler', function () { // NOSONAR - complex ok.
5263 let objName = $(this).prop('tagName'), val;
5264 let me; // to fix some special case indicator not at same level with input, need to find by name.
5265
5266 if ('DIV' === objName) { // ui dropdown select.
5267 val = $(this).dropdown('get value');
5268 } else if ($(this).is(':checkbox')) {
5269 val = $(this).is(":checked") ? '1' : '0';
5270 if ($(this).attr('name') === 'mainwp_show_widgets[]') {
5271 if ($('input[type="checkbox"][name="mainwp_show_widgets[]"]:not(:checked)').length == 0) {
5272 val = 'all';
5273 }
5274 } else if ($(this).attr('inverted-value')) {
5275 val = val === '1' ? '0' : '1'; // to fix compatible with some case checked is disable, value is 0.
5276 }
5277 } else {
5278 val = $(this).val();
5279 if ($(this).attr('name') === 'mainwp_rest_api_key_edit_pers') {
5280 val = val.split(',').length;
5281 } else if ($(this).attr('name') === 'cost_tracker_custom_product_types[title][]') {
5282 val = $('input[name="cost_tracker_custom_product_types[title][]"]').length; // default 0.
5283 me = $('.settings-field-indicator-wrapper.default-product-categories');
5284 } else if ($(this).attr('name') === 'cost_tracker_custom_payment_methods[title][]') {
5285 val = $('input[name="cost_tracker_custom_payment_methods[title][]"]').length; // default 0.
5286 me = $('.settings-field-indicator-wrapper.custom-payment-methods');
5287 }
5288 }
5289
5290 if (me === undefined) {
5291 mainwp_settings_fields_value_on_change(this, val);
5292 } else {
5293 mainwp_settings_fields_value_on_change(me, val);
5294 }
5295 });
5296
5297 let mainwp_settings_fields_value_on_change = function (obj, val) {
5298 let parent = $(obj).closest('.settings-field-indicator-wrapper');
5299 if (parent.length) {
5300 let defval = $(parent).attr('default-indi-value') ?? ''; // put default-indi-value at wrapper because semantic ui some case move class of input too input's parent.
5301 let indiObj = parent.find('.settings-field-icon-indicator');
5302 if (indiObj.length) {
5303 if (val == defval || ('0' == val && '' === defval)) { // empty and zero are same.
5304 $(indiObj).removeClass('visible-indicator');
5305 } else {
5306 $(indiObj).addClass('visible-indicator');
5307 }
5308 }
5309 }
5310 }
5311 });
5312
5313
5314
5315 let mainwp_common_filter_show_segments_modal = function (loadCallback) {
5316 jQuery('#mainwp-common-filter-segment-modal').modal({
5317 allowMultiple: false,
5318 onShow: function () {
5319 if (typeof loadCallback == 'function') {
5320 loadCallback();
5321 }
5322 }
5323 }).modal('show');
5324 };
5325
5326 jQuery(function ($) {
5327 if (!globalThis.mainwpSegmentModalUiHandle) {
5328 globalThis.mainwpSegmentModalUiHandle = (function () {
5329 let _instance = {
5330 loadingStatus: function () {
5331 $('#mainwp-common-filter-edit-segment-status').html('<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Loading segments. Please wait...')).show();
5332 },
5333 savingStatus: function () {
5334 $('#mainwp-common-filter-edit-segment-status').html('<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Saving segment. Please wait...')).show();
5335 },
5336 deletingStatus: function () {
5337 $('#mainwp-common-filter-edit-segment-status').html('<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Deleting segment. Please wait...')).show();
5338
5339 },
5340 showStatus: function (status, addClass) {
5341 if (addClass) {
5342 $('#mainwp-common-filter-edit-segment-status').addClass(addClass);
5343 }
5344 $('#mainwp-common-filter-edit-segment-status').html(status).show();
5345 },
5346 hideSegmentStatus: function () {
5347 $('#mainwp-common-filter-edit-segment-status').removeClass('red green').hide();
5348 },
5349 showSegment: function (btnObj) {
5350 jQuery('#mainwp-common-filter-segment-modal > div.header').html(MainWP.I18n.t('Save Segment'));
5351 jQuery('#mainwp-common-filter-segment-edit-fields').show();
5352 jQuery('#mainwp-common-filter-edit-segment-save').show();
5353 jQuery('#mainwp-common-filter-segment-select-fields').hide();
5354 jQuery('#mainwp-common-filter-select-segment-choose-button').hide();
5355 jQuery('#mainwp-common-filter-select-segment-delete-button').hide();
5356 jQuery('#mainwp-common-filter-edit-segment-name').val(jQuery(btnObj).attr('selected-segment-name'));
5357 this.hideSegmentStatus();
5358 mainwp_common_filter_show_segments_modal();
5359 },
5360 loadSegment: function (loadCallback) {
5361 jQuery('#mainwp-common-filter-segment-edit-fields').hide();
5362 jQuery('#mainwp-common-filter-edit-segment-save').hide();
5363 jQuery('#mainwp-common-filter-segment-modal > div.header').html(MainWP.I18n.t('Load Segment'));
5364 jQuery('#mainwp-common-filter-segment-select-fields').show();
5365 jQuery('#mainwp-common-filter-select-segment-choose-button').show();
5366 jQuery('#mainwp-common-filter-select-segment-delete-button').show();
5367 this.hideSegmentStatus();
5368 mainwp_common_filter_show_segments_modal(loadCallback);
5369 },
5370 showResults: function (result) {
5371 jQuery('#mainwp-common-filter-edit-segment-status').hide();
5372 jQuery('#mainwp-common-filter-segments-lists-wrapper').html(result);
5373 jQuery('#mainwp-common-filter-segments-lists-wrapper .ui.dropdown').dropdown();
5374 jQuery('#mainwp-common-filter-segment-select-fields').show();
5375 }
5376 }
5377 return _instance;
5378 })();
5379 }
5380
5381 });
5382
5383 let mainwp_overview_gridstack_save_layout = function (item_id, grid) {
5384
5385 if (!grid?.engine?.nodes) {
5386 return;
5387 }
5388
5389 let orders = [];
5390 let wgIds = [];
5391
5392 grid.engine.nodes.forEach(function (node) {
5393 if (!node?.el?.id) {
5394 return;
5395 }
5396
5397 let obj = {
5398 "x": node.x ?? 0,
5399 "y": node.y ?? 0,
5400 "w": node.w ?? 4,
5401 "h": node.h ?? 4
5402 };
5403 orders.push(obj);
5404 wgIds.push(node.el.id);
5405 });
5406
5407 if (wgIds.length === 0) {
5408 return;
5409 }
5410
5411 let postVars = {
5412 action: 'mainwp_widgets_order',
5413 page: page_sortablewidgets,
5414 order: JSON.stringify(orders),
5415 wgids: JSON.stringify(wgIds),
5416 item_id: item_id,
5417 page_widget: page_widget
5418 };
5419 jQuery.post(ajaxurl, mainwp_secure_data(postVars), function () { });
5420 }
5421
5422 globalThis.mainwp_init_ui_calendar = ($selectors) => {
5423 jQuery($selectors).calendar({
5424 type: 'date',
5425 monthFirst: false,
5426 today: true,
5427 touchReadonly: false,
5428 formatter: {
5429 date: function (date) {
5430 if (!date) return '';
5431 let day = date.getDate();
5432 let month = date.getMonth() + 1;
5433 let year = date.getFullYear();
5434
5435 if (month < 10) {
5436 month = '0' + month;
5437 }
5438 if (day < 10) {
5439 day = '0' + day;
5440 }
5441 return year + '-' + month + '-' + day;
5442 }
5443 }
5444 });
5445
5446 }
5447
5448
5449 jQuery(document).ready(function () {
5450 jQuery('.dt-scroll-head').css({
5451 'overflow-x': 'auto'
5452 }).on('scroll', function () {
5453 let scrollBody = jQuery(this).parent().find('.dt-scroll-body').get(0);
5454 scrollBody.scrollLeft = this.scrollLeft;
5455 jQuery(scrollBody).trigger('scroll');
5456 });
5457 });
5458
5459 // Function to check valid email using regular expression.
5460 const mainwp_validate_email = function (email) {
5461 const re = /^[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,}$/;
5462 return re.test(email);
5463 }
5464
5465
5466 jQuery(function ($) {
5467
5468 $(document).on('click', '#delete_uptime_monitor_btn', function () {
5469 let is_sub = $('#monitor_edit_is_sub_url')?.val();
5470
5471 let confirmation = MainWP.I18n.t("Are you sure you want to delete this uptime monitor?");
5472
5473 if (is_sub) {
5474 confirmation = MainWP.I18n.t("Are you sure you want to delete this uptime sub-page monitor?");
5475 }
5476
5477 mainwp_confirm(confirmation, () => {
5478 let wpid = $('#mainwp_edit_monitor_site_id').val();
5479 let moid = $('#mainwp_edit_monitor_id').val();
5480
5481 mainwp_uptime_monitoring_remove(wpid, moid);
5482 }, false, false, true);
5483 });
5484
5485 let mainwp_uptime_monitoring_remove = function (wpid, moid) {
5486
5487 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Removing Uptime Monitor...'), 'green');
5488
5489 let data = mainwp_secure_data({
5490 action: 'mainwp_uptime_monitoring_remove_monitor',
5491 wpid: wpid,
5492 moid: moid
5493 });
5494
5495 jQuery.post(ajaxurl, data, function (response) {
5496 if (response?.success) {
5497 feedback('mainwp-message-zone', MainWP.I18n.t('Monitor have been removed.'), 'green');
5498 setTimeout(function () {
5499 mainwp_forceReload('admin.php?page=managesites&id=' + wpid);
5500 }, 2000);
5501
5502 } else if (response?.error) {
5503 feedback('mainwp-message-zone', response.error, 'red');
5504 } else {
5505 feedback('mainwp-message-zone', MainWP.I18n.t('Undefined error. Please try again.'), 'red');
5506 }
5507 }, 'json');
5508 return false;
5509 };
5510
5511 $(document).on('click', '#increase-connection-security-btn', function () {
5512 feedback('mainwp-message-zone', '<i class="notched circle loading icon"></i> ' + MainWP.I18n.t('Encryption in progress! Securing your OpenSSL private keys, this may take a few moments. Please wait until completed.'), 'green');
5513 let data = mainwp_secure_data({
5514 action: 'mainwp_increase_connection_security',
5515 });
5516 jQuery.post(ajaxurl, data, function (response) {
5517 if (response?.success) {
5518 setTimeout(function () {
5519 mainwp_forceReload();
5520 }, 2000);
5521
5522 } else if (response?.error) {
5523 feedback('mainwp-message-zone', response.error, 'red');
5524 } else {
5525 feedback('mainwp-message-zone', MainWP.I18n.t('Undefined error. Please try again.'), 'red');
5526 }
5527 }, 'json');
5528 return false;
5529 });
5530 jQuery('#module-update-logs-db-requirement').on('click', function () {
5531 let msg = MainWP.I18n.t('Are you sure?');
5532 mainwp_confirm(msg, () => {
5533 jQuery(this).closest('.ui.message').fadeOut();
5534 mainwp_module_logs_start_update_dismissed_db();
5535 });
5536 return false;
5537 });
5538 });
5539
5540
5541 jQuery(document).on('click', '#mainwp-sites-changes-filter-toggle-button', function () {
5542 jQuery('#mainwp-module-log-filters-row').toggle(300);
5543 return false;
5544 });
5545
5546 jQuery(document).on('click', '#mainwp-insights-filter-toggle-button', function () {
5547 jQuery('#mainwp-module-log-overview-sub-header').toggle(300);
5548 return false;
5549 });
5550
5551
5552
5553 let logs_update_db_cancelled = false;
5554 let mainwp_module_logs_start_update_dismissed_db = function () {
5555 let data = mainwp_secure_data({
5556 action: 'mainwp_module_log_update_dismissed_db',
5557 });
5558 if (logs_update_db_cancelled) {
5559 mainwp_set_message_zone('#module-log-update-dissmised-logs-running', '<i class="close icon"></i>' + MainWP.I18n.t("User cancelled the 'Sites Changes' database update process."), 'green');
5560 } else {
5561 mainwp_set_message_zone('#module-log-update-dissmised-logs-running', '<i class="ui active inline loader tiny"></i> ' + MainWP.I18n.t('Updating the \'Sites Changes\' database. Click %1here%2 to cancel.', '<a href="javascript:void(0);" id="module-update-logs-db-cancel">', '</a>'), 'green');
5562 }
5563 jQuery.post(ajaxurl, data, function (response) {
5564 let status = response?.status ?? '';
5565 if (response.error) {
5566 mainwp_set_message_zone('#module-log-update-dissmised-logs-running', '<i class="close icon"></i>' + response.error, 'red');
5567 } else if (status === 'finished') {
5568 mainwp_set_message_zone('#module-log-update-dissmised-logs-running', '<i class="close icon"></i>' + MainWP.I18n.t('Logs records has been updated successfully.'), 'green');
5569 } else if (status === 'running' && !logs_update_db_cancelled) {
5570 setTimeout(function () {
5571 mainwp_module_logs_start_update_dismissed_db();
5572 }, 500);
5573 }
5574 }, 'json');
5575 }
5576
5577 jQuery(document).on('click', '#module-update-logs-db-cancel', function () {
5578 logs_update_db_cancelled = true;
5579 let data = mainwp_secure_data({
5580 action: 'mainwp_module_log_cancel_update_dismissed_db',
5581 });
5582 jQuery(this).closest('.ui.message').fadeOut(300);
5583 jQuery.post(ajaxurl, data, function (response) {
5584 //ok.
5585 }, 'json');
5586 return false;
5587 });
5588
5589
5590
5591 let get_local_date_string = function () {
5592 const today = new Date();
5593 const y = today.getFullYear();
5594 const m = String(today.getMonth() + 1).padStart(2, '0'); // month starts from 0
5595 const d = String(today.getDate()).padStart(2, '0');
5596 return `${y}-${m}-${d}`;
5597 }
5598
5599 function mainwp_forceReload(targetUrl) {
5600 const url = targetUrl || globalThis.location.href;
5601 // Navigate to URL (force reload from server)
5602 globalThis.location.href = url;
5603 }
5604
5605 class TablePersistentState {
5606 constructor(table, options = {}) {
5607 if (!table || !(table instanceof HTMLElement)) {
5608 throw new Error('TablePersistentState requires a table element');
5609 }
5610
5611 this.table = table;
5612 this.tableId = table.id;
5613 this.headers = table.querySelectorAll(
5614 options.headerSelector || '.handle-cols-sorting'
5615 );
5616
5617 this.options = {
5618 storage: options.storage !== false, // default true
5619 storagePrefix: options.storagePrefix || 'mainwp_tables_sort_state',
5620 onPersist: options.onPersist || null,
5621 defaultSort: options.defaultSort || null, // column, direction
5622 };
5623
5624 this.init();
5625 }
5626
5627 /* ---------- Storage ---------- */
5628
5629 get storageKey() {
5630 return `${this.options.storagePrefix}:${this.tableId}`;
5631 }
5632
5633 saveState(column, direction) {
5634 if (!this.options.storage || !this.tableId) return;
5635
5636 localStorage.setItem(
5637 this.storageKey,
5638 JSON.stringify({ column, direction })
5639 );
5640 }
5641
5642 loadState() {
5643 if (!this.options.storage || !this.tableId) return null;
5644
5645 try {
5646 return JSON.parse(localStorage.getItem(this.storageKey));
5647 } catch {
5648 return null;
5649 }
5650 }
5651
5652 /* ---------- UI helpers ---------- */
5653
5654 clearIndicators() {
5655 this.headers.forEach(th => {
5656 th.classList.remove('sorted-asc', 'sorted-desc');
5657 th.removeAttribute('aria-sort');
5658 });
5659 }
5660
5661 applyIndicator(th, direction) {
5662 th.classList.add(direction === 'asc' ? 'sorted-asc' : 'sorted-desc');
5663 th.setAttribute('aria-sort', direction);
5664 }
5665
5666 toggleDirection(current) {
5667 return current === 'asc' ? 'desc' : 'asc';
5668 }
5669
5670 /* ---------- Sorting flow ---------- */
5671
5672 persistState(column, direction, th = null, persist = true, isrestore = false) {
5673 if (th) {
5674 this.clearIndicators();
5675 this.applyIndicator(th, direction);
5676 }
5677
5678 if (persist) {
5679 this.saveState(column, direction);
5680 }
5681
5682 if (typeof this.options.onPersist === 'function') {
5683 this.options.onPersist({
5684 table: this.table,
5685 column,
5686 direction,
5687 isrestore
5688 });
5689 }
5690 }
5691
5692 /* ---------- Init ---------- */
5693
5694 restore() {
5695 const saved = this.loadState() || this.options.defaultSort;
5696 if (!saved) return;
5697
5698 const th = this.table.querySelector(
5699 `[data-key="${saved.column}"]`
5700 );
5701
5702 if (th) {
5703 this.persistState(saved.column, saved.direction, th, false, true);
5704 }
5705 }
5706
5707 bindEvents() {
5708 this.headers.forEach(th => {
5709 th.addEventListener('click', () => {
5710 const column = th.dataset.key;
5711 const isAsc = th.classList.contains('sorted-asc');
5712 const direction = this.toggleDirection(isAsc ? 'asc' : 'desc');
5713
5714 this.persistState(column, direction, th);
5715 });
5716 });
5717 }
5718
5719 init() {
5720 if (!this.tableId && this.options.storage) {
5721 console.warn('TablePersistentState: table has no id, storage disabled');
5722 }
5723
5724 this.restore();
5725 this.bindEvents();
5726 }
5727 }
5728