PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
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
← All changes | assets/js/mainwp-rest-api.js +678 -41 4.6.0.1 → 6.2.2 View file →
@@ -1,89 +1,86 @@
1 +let bulk_RestAPIMaxThreads = 1;
2 +let bulk_RestAPICurrentThreads = 0;
3 +let bulk_RestAPITotal = 0;
4 +let bulk_RestAPIFinished = 0;
5 +let bulk_RestAPITaskRunning = false;
1 6
2 -bulk_RestAPIMaxThreads = 1;
3 -bulk_RestAPICurrentThreads = 0;
4 -bulk_RestAPITotal = 0;
5 -bulk_RestAPIFinished = 0;
6 -bulk_RestAPITaskRunning = false;
7 -
8 -jQuery(document).ready(function ($) {
7 +jQuery(function ($) {
9 8 $('body').on('click', '.copy-to-clipboard', function () {
10 - alert('Copied!');
9 + $('#mainwp-api-key-copied-confirm-modal').modal('show');
11 10 });
12 11 // Trigger Manage Bulk Actions
13 12 jQuery(document).on('click', '#mainwp-do-rest-api-bulk-actions', function () {
14 - var action = jQuery("#mainwp-rest-api-bulk-actions-menu").dropdown("get value");
15 - if (action == 'delete') {
16 -
17 - if (bulk_RestAPITaskRunning) {
18 - return false;
19 - }
13 + let action = jQuery("#mainwp-rest-api-bulk-actions-menu").dropdown("get value");
14 + if (action == 'delete' && !bulk_RestAPITaskRunning) {
20 15 mainwp_restapi_bulk_remove_keys_confirm();
21 - return false;
22 16 }
23 17 return false;
24 18 });
25 19
20 + // Initialize Application Passwords functionality
21 + if ($("#rest-application-passwords-settings").length > 0) {
22 + init_application_passwords($);
23 + }
26 24 });
27 25
28 -mainwp_restapi_remove_key_confirm = function (pCheckedBox) {
29 - confirmMsg = __("You are about to delete the selected REST API Key?");
30 - mainwp_confirm(confirmMsg, _callback = function () {mainwp_restapi_bulk_remove_specific(pCheckedBox); });
26 +let mainwp_restapi_remove_key_confirm = function (pCheckedBox) {
27 + let confirmMsg = MainWP.I18n.t("You are about to delete the selected REST API Key?");
28 + mainwp_confirm(confirmMsg, function () { mainwp_restapi_bulk_remove_specific(pCheckedBox); });
31 29 }
32 30
33 -mainwp_restapi_bulk_remove_keys_confirm = function () {
34 - confirmMsg = __("You are about to delete the selected REST API Key(s)?");
35 - mainwp_confirm(confirmMsg, _callback = function () { mainwp_restapi_bulk_init(); mainwp_restapi_remove_keys_next(); });
31 +let mainwp_restapi_bulk_remove_keys_confirm = function () {
32 + let confirmMsg = MainWP.I18n.t("You are about to delete the selected REST API Key(s)?");
33 + mainwp_confirm(confirmMsg, function () { mainwp_restapi_bulk_init(); mainwp_restapi_remove_keys_next(); });
36 34 }
37 35
38 -mainwp_restapi_bulk_init = function () {
36 +let mainwp_restapi_bulk_init = function () {
39 37 jQuery('#mainwp-message-zone-apikeys').hide();
40 - if (bulk_RestAPITaskRunning == false) {
38 + if (!bulk_RestAPITaskRunning) {
41 39 bulk_RestAPICurrentThreads = 0;
42 40 bulk_RestAPITotal = 0;
43 41 bulk_RestAPIFinished = 0;
44 - jQuery('#mainwp-rest-api-body-table .check-column INPUT:checkbox').each(function () {
42 + jQuery('.mainwp-rest-api-body-table-manage .check-column INPUT:checkbox').each(function () {
45 43 jQuery(this).attr('status', 'queue')
46 44 });
47 45 }
48 46 };
49 47
50 -
51 -mainwp_restapi_remove_keys_next = function () {
52 - while ((checkedBox = jQuery('#mainwp-rest-api-body-table .check-column INPUT:checkbox:checked[status="queue"]:first')) && (checkedBox.length > 0) && (bulk_RestAPICurrentThreads < bulk_RestAPIMaxThreads)) {
48 +let mainwp_restapi_remove_keys_next = function () {
49 + while ((checkedBox = jQuery('.mainwp-rest-api-body-table-manage .check-column INPUT:checkbox:checked[status="queue"]:first')) && (checkedBox.length > 0) && (bulk_RestAPICurrentThreads < bulk_RestAPIMaxThreads)) { // NOSONAR - variables modified in other functions.
53 50 mainwp_restapi_bulk_remove_specific(checkedBox);
54 51 }
55 - if ((bulk_RestAPITotal > 0) && (bulk_RestAPIFinished == bulk_RestAPITotal)) {
56 - setHtml('#mainwp-message-zone-apikeys', __("Process completed. Reloading page..."));
52 + if ((bulk_RestAPITotal > 0) && (bulk_RestAPIFinished == bulk_RestAPITotal)) { // NOSONAR - modified outside the function.
53 + setHtml('#mainwp-message-zone-apikeys', MainWP.I18n.t("Process completed. Reloading page..."));
57 54 setTimeout(function () {
58 - window.location.href = location.href;
55 + mainwp_forceReload();
59 56 }, 3000);
60 57 }
61 58 }
62 59
63 -mainwp_restapi_bulk_remove_specific = function (pCheckedBox) {
60 +let mainwp_restapi_bulk_remove_specific = function (pCheckedBox) {
64 61 pCheckedBox.attr('status', 'running');
65 - var rowObj = pCheckedBox.closest('tr');
62 + let rowObj = pCheckedBox.closest('tr');
66 63 bulk_RestAPICurrentThreads++;
67 64
68 - var id = rowObj.attr('key-ck-id');
69 -
65 + let id = rowObj.attr('key-ck-id');
70 66 rowObj.html('<td colspan="999"><i class="notched circle loading icon"></i> ' + 'Deleting ...' + '</td>');
71 -
72 - var data = mainwp_secure_data({
67 + let data = mainwp_secure_data({
73 68 action: 'mainwp_rest_api_remove_keys',
74 - keyId: id
69 + keyId: id,
70 + api_ver: rowObj.closest('tbody').attr('id') === 'mainwp-rest-api-v2-body-table' ? 'v2' : 'v1'
75 71 });
72 +
76 73 jQuery.post(ajaxurl, data, function (response) {
77 74 bulk_RestAPICurrentThreads--;
78 75 bulk_RestAPIFinished++;
79 76 rowObj.html('<td colspan="999"></td>');
80 - var result = '';
81 - var error = '';
77 + let result = '';
78 + let error = '';
82 79 if (response.error != undefined) {
83 80 error = response.error;
84 81 } else if (response.success == 'SUCCESS') {
85 - result = __('The REST API Key has been deleted.');
82 + result = MainWP.I18n.t('The REST API Key has been deleted.');
86 83 }
87 84 if (error != '') {
88 85 rowObj.html('<td colspan="999"><i class="red times icon"></i>' + error + '</td>');
89 86 } else {
@@ -93,7 +90,647 @@
93 90 jQuery('tr[key-ck-id=' + id + ']').fadeOut(1000);
94 91 }, 3000);
95 92
96 93 mainwp_restapi_remove_keys_next();
97 - }, 'json');
94 + },
95 + "json"
96 + );
98 97 };
99 98
99 +/**
100 + * Application Passwords functionality
101 + */
102 +const init_application_passwords = ($) => {
103 + const app_pass_section = $("#rest-application-passwords-settings");
104 + const create_modal = $("#mainwp-create-application-password-modal");
105 + const success_modal = $("#mainwp-application-password-success-modal");
106 + const app_pass_name_input = $("#mainwp-app-password-name-input");
107 + const app_pass_tbody = $("#mainwp-application-password-table-body");
108 + const edit_modal = $("#mainwp-edit-application-password-modal");
109 + const edit_name_input = $("#mainwp-app-password-edit-name-input");
110 + const edit_uuid_input = $("#mainwp-app-password-edit-uuid");
111 + const edit_user_id_input = $("#mainwp-app-password-edit-user-id");
112 + const has_user_col = $('#mainwp-application-password-table thead th.mainwp-col-user').length > 0;
113 + const current_user_name = $('#rest-application-passwords-settings').data('current-user-name') || '';
114 + const message_zone = $("#mainwp-message-zone-app-passwords");
115 +
116 + /**
117 + * Helper function to escape HTML
118 + */
119 + const escape_html = (text) => {
120 + const map = {
121 + "&": "&amp;",
122 + "<": "&lt;",
123 + ">": "&gt;",
124 + '"': "&quot;",
125 + "'": "&#039;",
126 + };
127 + return text.replace(/[&<>"']/g, (m) => map[m]); // NOSONAR ok.
128 + };
129 +
130 + /**
131 + * Helper function to clear messages
132 + */
133 + const clear_messages = () => {
134 + message_zone.hide().html("");
135 + };
136 +
137 + /**
138 + * Helper function to show messages
139 + */
140 + const show_message = (message, type) => {
141 + clear_messages();
142 +
143 + const class_name = type === "error" ? "red" : "green";
144 + const html = `<div class="ui ${class_name} message">
145 + <i class="close icon"></i>
146 + ${message}
147 + </div>`;
148 +
149 + message_zone.html(html).show();
150 + message_zone.find(".close.icon").on("click", () => {
151 + message_zone.fadeOut();
152 + });
153 +
154 + setTimeout(() => {
155 + message_zone.fadeOut();
156 + }, 3000);
157 + };
158 +
159 + /**
160 + * Helper function to format date like PHP format_timestamp
161 + * Format: "January 1, 2026 10:15 am"
162 + */
163 + const format_timestamp = (timestamp) => {
164 + const date = new Date(timestamp * 1000);
165 +
166 + // Get month name
167 + const month_names = [
168 + "January",
169 + "February",
170 + "March",
171 + "April",
172 + "May",
173 + "June",
174 + "July",
175 + "August",
176 + "September",
177 + "October",
178 + "November",
179 + "December",
180 + ];
181 + const month = month_names[date.getMonth()];
182 +
183 + // Get day, year
184 + const day = date.getDate();
185 + const year = date.getFullYear();
186 +
187 + // Get hours and minutes
188 + let hours = date.getHours();
189 + const minutes = date.getMinutes().toString().padStart(2, "0");
190 + const ampm = hours >= 12 ? "pm" : "am";
191 + hours = hours % 12;
192 + hours = hours ? hours : 12; // NOSONAR - noopener - hours 0 should be 12.
193 +
194 + return `${month} ${day}, ${year} ${hours}:${minutes} ${ampm}`;
195 + };
196 +
197 + /**
198 + * Helper function to add password row to table
199 + */
200 + const add_password_row = (item) => {
201 + const created_str = format_timestamp(item.created);
202 + const table_el = $('#mainwp-application-password-table');
203 + // Get DataTable instance
204 + const table = window.mainwp_app_passwords_table; // NOSONAR - noopener - global variable.
205 +
206 + if (!table) {
207 + console.error("DataTable not initialized");
208 + return;
209 + }
210 +
211 + // Check manage capability from table data attribute
212 + const can_manage_table = table_el.data('can-manage') == 1;
213 + const can_edit_table = table_el.data('can-edit') == 1;
214 +
215 + // Create row HTML with proper data-order attributes
216 + const row_html = `<tr data-uuid="${item.uuid}" data-user-id="${item.user_id || ''}">
217 + <td class="check-column">
218 + <div class="ui checkbox">
219 + <input type="checkbox" value="${item.uuid}" name="" ${can_manage_table ? '' : 'disabled'} />
220 + </div>
221 + </td>
222 + <td>${escape_html(item.name)}</td>
223 + ${has_user_col ? `<td>${escape_html(current_user_name)}</td>` : ''}
224 + <td data-order="${item.created}">${created_str}</td>
225 + <td data-order="0">&mdash;</td>
226 + <td>&mdash;</td>
227 + <td class="right aligned">
228 + ${can_edit_table ? `<button type="button" class="ui mini basic button mainwp-edit-application-password" data-uuid="${item.uuid}" data-user-id="${item.user_id || ''}" data-name="${escape_html(item.name)}">${MainWP.I18n.t("Edit")}</button>` : ''}
229 + ${can_manage_table ? `<button type="button" class="ui mini grey basic button mainwp-revoke-application-password" data-uuid="${item.uuid}">${MainWP.I18n.t("Revoke")}</button>` : ''}
230 + </td>
231 + </tr>`;
232 +
233 + // Add row using DataTables API with DOM node
234 + const row_node = table.row.add($(row_html)[0]).draw(false).node();
235 +
236 + // Initialize Semantic UI checkbox
237 + $(row_node).find(".ui.checkbox").checkbox();
238 + };
239 +
240 + /**
241 + * Open edit modal
242 + */
243 + app_pass_tbody.on('click', '.mainwp-edit-application-password', (e) => {
244 + e.preventDefault();
245 + const btn = $(e.currentTarget);
246 + const uuid = btn.data('uuid');
247 + const user_id = btn.data('user-id');
248 + const name = btn.data('name');
249 +
250 + edit_uuid_input.val(uuid);
251 + edit_user_id_input.val(user_id);
252 + edit_name_input.val(name);
253 +
254 + edit_modal.modal('show');
255 + });
256 +
257 + /**
258 + * Submit edit application password
259 + */
260 + $('#mainwp-edit-app-password-submit').on('click', (e) => {
261 + e.preventDefault();
262 + const uuid = edit_uuid_input.val();
263 + const user_id = edit_user_id_input.val();
264 + const name = (edit_name_input.val() || '').trim();
265 + if (!name) {
266 + edit_name_input.trigger('focus');
267 + show_message(MainWP.I18n.t('Please enter an application name.'), 'error');
268 + return false;
269 + }
270 +
271 + const data = mainwp_secure_data({
272 + action: 'mainwp_application_password_update',
273 + uuid: uuid,
274 + user_id: user_id,
275 + name: name,
276 + });
277 +
278 + $.post(ajaxurl, data, (resp) => { // NOSONAR - noopener - complex.
279 + if (resp?.success) {
280 + try {
281 + const table = window.mainwp_app_passwords_table; // NOSONAR - noopener - global variable.
282 + const tr = $('#mainwp-application-password-table tbody tr[data-uuid="' + uuid + '"]');
283 + if (tr.length) {
284 + // Update name cell
285 + const name_cell = tr.find('td').eq(1);
286 + name_cell.text(name);
287 + // Update buttons aria/data
288 + const edit_btn = tr.find('.mainwp-edit-application-password');
289 + if (edit_btn.length) {
290 + edit_btn.attr('data-name', name);
291 + edit_btn.attr('aria-label', MainWP.I18n.t('Rename "%s"').replace('%s', name));
292 + }
293 + const revoke_btn = tr.find('.mainwp-revoke-application-password');
294 + if (revoke_btn.length) {
295 + revoke_btn.attr('aria-label', MainWP.I18n.t('Revoke "%s"').replace('%s', name));
296 + }
297 + if (table) {
298 + table.row(tr).invalidate().draw(false);
299 + }
300 + }
301 + show_message(MainWP.I18n.t('Application password updated successfully.'), 'success');
302 + edit_modal.modal('hide');
303 + } catch {
304 + mainwp_forceReload();
305 + }
306 + } else {
307 + const msg = (resp?.data?.message) ?? MainWP.I18n.t('Failed to update Application Password.');
308 + show_message(msg, 'error');
309 + }
310 + }, 'json');
311 + });
312 +
313 + /**
314 + * Helper function to revoke multiple passwords
315 + */
316 + const revoke_multiple_passwords = (items) => {
317 + const data = mainwp_secure_data({
318 + action: "mainwp_application_password_delete_multiple",
319 + items: items,
320 + });
321 +
322 + $.post(
323 + ajaxurl,
324 + data,
325 + (response) => {
326 + if (response.success) {
327 + const table = window.mainwp_app_passwords_table; // NOSONAR - noopener - global variable.
328 +
329 + if (table) {
330 + // Remove all selected rows using DataTables API
331 + items.forEach((it) => {
332 + const row = table.row(`[data-uuid="${it.uuid}"]`);
333 + if (row.length) {
334 + row.remove();
335 + }
336 + });
337 +
338 + // Redraw table
339 + table.draw(false);
340 + }
341 +
342 + show_message(
343 + MainWP.I18n.t("Selected application passwords have been revoked."),
344 + "success"
345 + );
346 + } else {
347 + show_message(
348 + response.data.message || MainWP.I18n.t("An error occurred."),
349 + "error"
350 + );
351 + }
352 + },
353 + "json"
354 + ).fail(() => {
355 + show_message(
356 + MainWP.I18n.t(
357 + "An error occurred while revoking the application passwords."
358 + ),
359 + "error"
360 + );
361 + });
362 + };
363 +
364 + /**
365 + * Open create modal
366 + */
367 + $("#mainwp-create-application-password-button-top, #mainwp-create-application-password-button").on("click", () => {
368 + app_pass_name_input.val("");
369 + const submit_btn = $("#mainwp-create-app-password-submit");
370 + submit_btn.addClass("disabled");
371 +
372 + app_pass_name_input.off("input.create_modal").on("input.create_modal", () => {
373 + if (app_pass_name_input.val().trim().length > 0) {
374 + submit_btn.removeClass("disabled");
375 + } else {
376 + submit_btn.addClass("disabled");
377 + }
378 + });
379 +
380 + create_modal
381 + .modal({
382 + onApprove: () => { // NOSONAR - noopener - prevent close.
383 + const name = app_pass_name_input.val().trim();
384 +
385 + if (name.length === 0) {
386 + app_pass_name_input.trigger("focus");
387 + show_message(
388 + MainWP.I18n.t("Please enter an application name."),
389 + "error"
390 + );
391 + return false;
392 + }
393 +
394 + create_application_password(name);
395 + return false; // Prevent modal from closing
396 + },
397 + })
398 + .modal("show");
399 + });
400 +
401 + /**
402 + * Create new application password
403 + */
404 + const create_application_password = (name) => {
405 + clear_messages();
406 +
407 + const submit_button = $("#mainwp-create-app-password-submit");
408 + submit_button.addClass("loading disabled");
409 +
410 + const data = mainwp_secure_data({
411 + action: "mainwp_application_password_create",
412 + name: name,
413 + });
414 +
415 + $.post(
416 + ajaxurl,
417 + data,
418 + (response) => {
419 + submit_button.removeClass("loading disabled");
420 +
421 + if (response.success) {
422 + // Close create modal
423 + create_modal.modal("hide");
424 +
425 + // Show success modal with password
426 + $("#app-pass-success-name").text(response.data.item.name);
427 + $("#app-pass-success-value").val(response.data.password);
428 +
429 + success_modal
430 + .modal({
431 + closable: false,
432 + onHidden: () => {
433 + location.reload();
434 + },
435 + })
436 + .modal("show");
437 +
438 + show_message(
439 + MainWP.I18n.t("Application password created successfully!"),
440 + "success"
441 + );
442 + } else {
443 + create_modal.modal("hide");
444 + show_message(
445 + response.data.message || MainWP.I18n.t("An error occurred."),
446 + "error"
447 + );
448 + }
449 + },
450 + "json"
451 + ).fail(() => {
452 + submit_button.removeClass("loading disabled");
453 + create_modal.modal("hide");
454 + show_message(
455 + MainWP.I18n.t(
456 + "An error occurred while creating the application password."
457 + ),
458 + "error"
459 + );
460 + });
461 + };
462 +
463 + /**
464 + * Copy password to clipboard
465 + */
466 + $(document).on("click", ".copy-app-password", function () {
467 + const input = $("#app-pass-success-value");
468 + const value = input.val();
469 +
470 + if (navigator.clipboard && globalThis.isSecureContext) {
471 + navigator.clipboard.writeText(value);
472 + }
473 +
474 + const button = $(this);
475 + const original_text = button.html();
476 + button.html('<i class="check icon"></i> ' + MainWP.I18n.t("Copied!"));
477 +
478 + setTimeout(() => {
479 + button.html(original_text);
480 + }, 2000);
481 + });
482 +
483 + /**
484 + * Revoke single application password
485 + */
486 + app_pass_tbody.on("click", ".mainwp-revoke-application-password", (e) => {
487 + e.preventDefault();
488 +
489 + if (
490 + !confirm(
491 + MainWP.I18n.t(
492 + "Are you sure you want to revoke this password? This action cannot be undone."
493 + )
494 + )
495 + ) {
496 + return;
497 + }
498 +
499 + const button = $(e.currentTarget);
500 + const tr = button.closest("tr");
501 + const uuid = button.data("uuid");
502 + const user_id = button.data("user-id") || button.closest('tr').data('user-id') || '';
503 +
504 + clear_messages();
505 + button.prop("disabled", true).addClass("disabled loading");
506 +
507 + const data = mainwp_secure_data({
508 + action: "mainwp_application_password_delete",
509 + uuid: uuid,
510 + user_id: user_id,
511 + });
512 +
513 + $.post(
514 + ajaxurl,
515 + data,
516 + (response) => {
517 + button.prop("disabled", false).removeClass("disabled loading");
518 +
519 + if (response.success) {
520 + const table = window.mainwp_app_passwords_table; // NOSONAR - noopener - global variable.
521 +
522 + if (table) {
523 + // Remove row using DataTables API
524 + table.row(tr).remove().draw(false);
525 + } else {
526 + // Fallback to direct DOM manipulation
527 + tr.fadeOut(300, function () {
528 + tr.remove();
529 + });
530 + }
531 +
532 + show_message(
533 + MainWP.I18n.t("Application password revoked successfully."),
534 + "success"
535 + );
536 + } else {
537 + show_message(
538 + response.data.message || MainWP.I18n.t("An error occurred."),
539 + "error"
540 + );
541 + }
542 + },
543 + "json"
544 + ).fail(() => {
545 + button.prop("disabled", false).removeClass("disabled loading");
546 + show_message(
547 + MainWP.I18n.t(
548 + "An error occurred while revoking the application password."
549 + ),
550 + "error"
551 + );
552 + });
553 + });
554 +
555 + /**
556 + * Select checkboxes and disable/enable bulk actions
557 + */
558 + $('.mainwp-application-password-checkbox').on('change', function () {
559 + const all_checked = $('.mainwp-application-password-checkbox').is(':checked');
560 + if (all_checked > 0) {
561 + $("#mainwp-do-application-passwords-bulk-actions").removeClass('disabled');
562 + } else {
563 + $("#mainwp-do-application-passwords-bulk-actions").addClass('disabled');
564 + }
565 + });
566 +
567 + /**
568 + * Bulk actions
569 + */
570 + $("#mainwp-do-application-passwords-bulk-actions").on("click", (e) => {
571 + const selected = [];
572 + app_pass_tbody
573 + .find('.check-column input[type="checkbox"]:checked')
574 + .each(function () {
575 + const uuid = $(this).val();
576 + const user_id = $(this).data('user-id') || $(this).closest('tr').data('user-id') || '';
577 + if (uuid) {
578 + selected.push({ uuid: uuid, user_id: user_id });
579 + }
580 + });
581 +
582 + if (selected.length === 0) {
583 + show_message(
584 + MainWP.I18n.t("Please select at least one application password."),
585 + "error"
586 + );
587 + return false;
588 + }
589 +
590 + if (
591 + !confirm(
592 + MainWP.I18n.t(
593 + "Are you sure you want to revoke the selected passwords? This action cannot be undone."
594 + )
595 + )
596 + ) {
597 + return false;
598 + }
599 +
600 + revoke_multiple_passwords(selected);
601 + e.preventDefault();
602 + e.stopPropagation();
603 + return true;
604 + });
605 +
606 + /**
607 + * Close new password notice
608 + */
609 + app_pass_section.on(
610 + "click",
611 + ".new-application-password-notice .close.icon",
612 + function () {
613 + $(this).closest(".new-application-password-notice").fadeOut();
614 + }
615 + );
616 +
617 + /**
618 + * Enter key on name field
619 + */
620 + app_pass_name_input.on("keypress", (e) => {
621 + if (e.which === 13) {
622 + e.preventDefault();
623 + create_button.trigger("click");
624 + }
625 + });
626 +};
627 +
628 +/**
629 + * Initialize REST API Permission Chips
630 + */
631 +jQuery(document).ready(function($) { // NOSONAR - complex.
632 + let initPermissionChips = function() {
633 + $('.mainwp-rest-api-permission-chips').each(function() {
634 + let container = $(this);
635 + let hiddenInput = container.find('input[type="hidden"]');
636 + let chips = container.find('.mainwp-permission-chip:visible');
637 + let initValue = container.data('init-value') || '';
638 +
639 + let updateHiddenInput = function() {
640 + let selectedPermissions = [];
641 + container.find('.mainwp-permission-chip:visible').each(function() { // NOSONAR - levels deep.
642 + if ($(this).hasClass('active')) {
643 + let perms = $(this).data('permission').toString().split(',');
644 + perms.forEach(function(p) {
645 + if (p && !selectedPermissions.includes(p)) {
646 + selectedPermissions.push(p);
647 + }
648 + });
649 + }
650 + });
651 + hiddenInput.val(selectedPermissions.join(','));
652 + hiddenInput.trigger('change');
653 + };
654 +
655 + let initPermissions = new Set(
656 + initValue
657 + .split(',')
658 + .filter(function (p) { return p !== ''; })
659 + );
660 +
661 + chips.each(function() {
662 + let chip = $(this);
663 + let chipPerms = chip.data('permission').toString().split(',');
664 + let isActive = false;
665 +
666 + chipPerms.forEach(function(perm) {
667 + if (initPermissions.has(perm)) {
668 + isActive = true;
669 + }
670 + });
671 +
672 + if (isActive) {
673 + chip.addClass('active green');
674 + } else {
675 + chip.addClass('inactive grey');
676 + }
677 + });
678 +
679 + updateHiddenInput();
680 +
681 + chips.off('click.permission-chip').on('click.permission-chip', function(e) {
682 + e.preventDefault();
683 + let chip = $(this);
684 +
685 + if (chip.hasClass('active')) {
686 + chip.removeClass('active green').addClass('inactive grey');
687 + } else {
688 + chip.removeClass('inactive grey').addClass('active green');
689 + }
690 +
691 + updateHiddenInput();
692 + });
693 + });
694 + };
695 +
696 + initPermissionChips();
697 +
698 + $('#mainwp_rest_api_keys_compatible_v1').on('change', function() {
699 + let isV1 = $(this).is(':checked');
700 + let container = $('.mainwp-rest-api-permission-chips[data-api-version]');
701 +
702 + if (isV1) {
703 + container.attr('data-api-version', 'v1');
704 + container.find('.mainwp-v2-chip').hide();
705 + container.find('.mainwp-v1-chip').show();
706 + } else {
707 + container.attr('data-api-version', 'v2');
708 + container.find('.mainwp-v1-chip').hide();
709 + container.find('.mainwp-v2-chip').show();
710 + }
711 +
712 + container.find('.mainwp-permission-chip').removeClass('active');
713 + initPermissionChips();
714 + });
715 +
716 + let updateBulkActionsState = function() {
717 + let checkedCount = $('.mainwp-rest-api-body-table-manage .check-column INPUT:checkbox:checked').length;
718 + let dropdown = $('#mainwp-rest-api-bulk-actions-menu');
719 + let applyButton = $('#mainwp-do-rest-api-bulk-actions');
720 +
721 + if (checkedCount > 0) {
722 + dropdown.removeClass('disabled');
723 + applyButton.removeClass('disabled');
724 + } else {
725 + dropdown.addClass('disabled');
726 + dropdown.dropdown('clear');
727 + applyButton.addClass('disabled');
728 + }
729 + };
730 +
731 + updateBulkActionsState();
732 +
733 + $(document).on('change', '.mainwp-rest-api-body-table-manage .check-column INPUT:checkbox', function() {
734 + updateBulkActionsState();
735 + });
736 +});