Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/paid-memberships-pro/js/pmpro-admin.js

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + /**
2 + * Show a system prompt before redirecting to a URL.
3 + * Used for delete links/etc.
4 + * @param text The prompt, i.e. are you sure?
5 + * @param url The url to redirect to.
6 + */
7 + function pmpro_askfirst(text, url) {
8 + var answer = window.confirm(text);
9 +
10 + if (answer) {
11 + window.location = url;
12 + }
13 + }
14 +
15 + /**
16 + * Deprecated in v2.1
17 + * In case add-ons/etc are expecting the non-prefixed version.
18 + */
19 + if (typeof askfirst !== 'function') {
20 + function askfirst(text, url) {
21 + return pmpro_askfirst(text, url);
22 + }
23 + }
24 +
25 + /*
26 + * Toggle elements with a specific CSS class selector.
27 + * Used to hide/show sub settings when a main setting is enabled.
28 + * @since v2.1
29 + */
30 + function pmpro_toggle_elements_by_selector(selector, checked) {
31 + if (checked === undefined) {
32 + jQuery(selector).toggle();
33 + } else if (checked) {
34 + jQuery(selector).show();
35 + } else {
36 + jQuery(selector).hide();
37 + }
38 + }
39 +
40 + /*
41 + * Find inputs with a custom attribute pmpro_toggle_trigger_for,
42 + * and bind change to toggle the specified elements.
43 + * @since v2.1
44 + */
45 + jQuery(document).ready(function () {
46 + jQuery('input[pmpro_toggle_trigger_for]').on('change', function () {
47 + pmpro_toggle_elements_by_selector(jQuery(this).attr('pmpro_toggle_trigger_for'), jQuery(this).prop('checked'));
48 + });
49 + });
50 +
51 + // Admin Settings Code.
52 + jQuery(document).ready(function () {
53 + pmpro_admin_prep_click_events();
54 + });
55 +
56 + // Function to prep click events for admin settings.
57 + function pmpro_admin_prep_click_events() {
58 + /*
59 + * Toggle content within the settings sections boxes.
60 + * @since 2.9
61 + */
62 + jQuery('button.pmpro_section-toggle-button').on('click', function (event) {
63 + event.preventDefault();
64 +
65 + let thebutton = jQuery(event.target).parents('.pmpro_section').find('button.pmpro_section-toggle-button');
66 + let buttonicon = thebutton.children('.dashicons');
67 + let section = thebutton.closest('.pmpro_section');
68 + let sectioninside = section.children('.pmpro_section_inside');
69 +
70 + //let visibility = container.data('visibility');
71 + //let activated = container.data('activated');
72 + if (buttonicon.hasClass('dashicons-arrow-down-alt2')) {
73 + // Section is not visible. Show it.
74 + jQuery(sectioninside).show();
75 + jQuery(buttonicon).removeClass('dashicons-arrow-down-alt2');
76 + jQuery(buttonicon).addClass('dashicons-arrow-up-alt2');
77 + jQuery(section).attr('data-visibility', 'shown');
78 + jQuery(thebutton).attr('aria-expanded', 'true');
79 + } else {
80 + // Section is visible. Hide it.
81 + jQuery(sectioninside).hide();
82 + jQuery(buttonicon).removeClass('dashicons-arrow-up-alt2');
83 + jQuery(buttonicon).addClass('dashicons-arrow-down-alt2');
84 + jQuery(section).attr('data-visibility', 'hidden');
85 + jQuery(thebutton).attr('aria-expanded', 'false');
86 + }
87 + });
88 + }
89 +
90 + // Hide the popup if clicked outside the popup.
91 + jQuery(document).on('click', function (e) {
92 + // Check if the clicked element is the close button or outside the pmpro-popup-wrap
93 + if ( jQuery(e.target).closest('.pmpro-popup-wrap').length === 0 ) {
94 + jQuery('.pmpro-popup-overlay').hide();
95 + }
96 + });
97 +
98 + /** JQuery to hide the notifications. */
99 + jQuery(document).ready(function () {
100 + jQuery(document).on('click', '.pmpro-notice-button.notice-dismiss', function () {
101 + var notification_id = jQuery(this).val();
102 + var nonce = jQuery(this).data('nonce');
103 +
104 + var postData = {
105 + action: 'pmpro_hide_notice',
106 + notification_id: notification_id,
107 + nonce: nonce
108 + }
109 +
110 + jQuery.ajax({
111 + type: "POST",
112 + data: postData,
113 + url: ajaxurl,
114 + success: function (response) {
115 + ///console.log( notification_id );
116 + jQuery('#' + notification_id).hide();
117 + }
118 + })
119 +
120 + });
121 + });
122 +
123 + /* jQuery to hide the pause notification if the secondary button is pressed */
124 + jQuery(document).ready(function () {
125 + jQuery('#hide_pause_notification_button').click(function () {
126 + jQuery('#hide_pause_notification .notice-dismiss').click();
127 + });
128 + });
129 +
130 + /*
131 + * Create Webhook button for Stripe on the payment settings page.
132 + */
133 + jQuery(document).ready(function () {
134 + // Check that we are on payment settings page.
135 + if (!jQuery('#stripe_publishablekey').length || !jQuery('#stripe_secretkey').length || !jQuery('#pmpro_stripe_create_webhook').length) {
136 + return;
137 + }
138 +
139 + // Disable the webhook buttons if the API keys aren't complete yet.
140 + jQuery('#stripe_publishablekey,#stripe_secretkey').on('change keyup', function () {
141 + pmpro_stripe_check_api_keys();
142 + });
143 + pmpro_stripe_check_api_keys();
144 +
145 + // AJAX call to create webhook.
146 + jQuery('#pmpro_stripe_create_webhook').on('click', function (event) {
147 + event.preventDefault();
148 +
149 + var postData = {
150 + action: 'pmpro_stripe_create_webhook',
151 + secretkey: pmpro_stripe_get_secretkey(),
152 + }
153 + jQuery.ajax({
154 + type: "POST",
155 + data: postData,
156 + url: ajaxurl,
157 + success: function (response) {
158 + response = jQuery.parseJSON(response);
159 + ///console.log( response );
160 +
161 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('error')
162 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('notice-success')
163 +
164 + if (response.notice) {
165 + jQuery('#pmpro_stripe_webhook_notice').parent('div').addClass(response.notice);
166 + }
167 + if (response.message) {
168 + jQuery('#pmpro_stripe_webhook_notice').html(response.message);
169 + }
170 + if (response.success) {
171 + jQuery('#pmpro_stripe_create_webhook').hide();
172 + }
173 + }
174 + })
175 + });
176 +
177 + // AJAX call to delete webhook.
178 + jQuery('#pmpro_stripe_delete_webhook').on('click', function (event) {
179 + event.preventDefault();
180 +
181 + var postData = {
182 + action: 'pmpro_stripe_delete_webhook',
183 + secretkey: pmpro_stripe_get_secretkey(),
184 + }
185 +
186 + jQuery.ajax({
187 + type: "POST",
188 + data: postData,
189 + url: ajaxurl,
190 + success: function (response) {
191 + response = jQuery.parseJSON(response);
192 + ///console.log( response );
193 +
194 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('error')
195 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('notice-success')
196 +
197 + if (response.notice) {
198 + jQuery('#pmpro_stripe_webhook_notice').parent('div').addClass(response.notice);
199 + }
200 + if (response.message) {
201 + jQuery('#pmpro_stripe_webhook_notice').html(response.message);
202 + }
203 + if (response.success) {
204 + jQuery('#pmpro_stripe_create_webhook').show();
205 + }
206 + }
207 + })
208 + });
209 +
210 + // AJAX call to rebuild webhook.
211 + jQuery('#pmpro_stripe_rebuild_webhook').on('click', function (event) {
212 + event.preventDefault();
213 +
214 + var postData = {
215 + action: 'pmpro_stripe_rebuild_webhook',
216 + secretkey: pmpro_stripe_get_secretkey(),
217 + }
218 +
219 + jQuery.ajax({
220 + type: "POST",
221 + data: postData,
222 + url: ajaxurl,
223 + success: function (response) {
224 + response = jQuery.parseJSON(response);
225 + ///console.log( response );
226 +
227 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('error')
228 + jQuery('#pmpro_stripe_webhook_notice').parent('div').removeClass('notice-success')
229 +
230 + if (response.notice) {
231 + jQuery('#pmpro_stripe_webhook_notice').parent('div').addClass(response.notice);
232 + }
233 + if (response.message) {
234 + jQuery('#pmpro_stripe_webhook_notice').html(response.message);
235 + }
236 + if (response.success) {
237 + jQuery('#pmpro_stripe_create_webhook').hide();
238 + }
239 + }
240 + })
241 + });
242 + });
243 +
244 + // Disable the webhook buttons if the API keys aren't complete yet.
245 + function pmpro_stripe_check_api_keys() {
246 + if ((jQuery('#stripe_publishablekey').val().length > 0 && jQuery('#stripe_secretkey').val().length > 0) || jQuery('#live_stripe_connect_secretkey').val().length > 0) {
247 + jQuery('#pmpro_stripe_create_webhook').removeClass('disabled');
248 + jQuery('#pmpro_stripe_create_webhook').addClass('button-secondary');
249 + } else {
250 + jQuery('#pmpro_stripe_create_webhook').removeClass('button-secondary');
251 + jQuery('#pmpro_stripe_create_webhook').addClass('disabled');
252 + }
253 + }
254 +
255 + // User Fields Code.
256 + jQuery(document).ready(function () {
257 + pmpro_userfields_prep_click_events();
258 + });
259 +
260 + // Function to prep click events.
261 + function pmpro_userfields_prep_click_events() {
262 + // Whenever we make a change, warn the user if they try to navigate away.
263 + function pmpro_userfields_made_a_change() {
264 + window.onbeforeunload = function () {
265 + return true;
266 + };
267 + jQuery('#pmpro_userfields_savesettings').prop("disabled", false);
268 + }
269 +
270 + // Add group button.
271 + jQuery('#pmpro_userfields_add_group').unbind('click').on('click', function (event) {
272 + jQuery('#pmpro_userfields_add_group').parent('p').before(pmpro.user_fields_blank_group);
273 + pmpro_userfields_prep_click_events();
274 + jQuery('#pmpro_userfields_add_group').parent('p').prev().find('input').focus().select();
275 + pmpro_userfields_made_a_change();
276 + });
277 +
278 + // Delete group button.
279 + jQuery('.pmpro_userfield-group-actions button[name=pmpro_userfields_delete_group]').unbind('click').on('click', function (event) {
280 + var thegroup = jQuery(this).closest('.pmpro_userfield-group');
281 + var thename = thegroup.find('input[name=pmpro_userfields_group_name]').val();
282 + var answer;
283 + if (thename.length > 0) {
284 + answer = window.confirm('Delete the "' + thename + '" group?');
285 + } else {
286 + answer = window.confirm('Delete this group?');
287 + }
288 + if (answer) {
289 + thegroup.remove();
290 + pmpro_userfields_made_a_change();
291 + }
292 + });
293 +
294 + // Add field button.
295 + jQuery('button[name="pmpro_userfields_add_field"]').unbind('click').on('click', function (event) {
296 + var thefields = jQuery(event.target).closest('div.pmpro_userfield-group-actions').siblings('div.pmpro_userfield-group-fields');
297 + thefields.append(pmpro.user_fields_blank_field);
298 + pmpro_userfields_prep_click_events();
299 + thefields.children().last().find('.edit-field').click();
300 + thefields.children().last().find('input[name="pmpro_userfields_field_label"]').focus().select();
301 + pmpro_userfields_made_a_change();
302 + });
303 +
304 + // Delete field button.
305 + jQuery('.pmpro_userfield-field-options a.delete-field, .pmpro_userfield-field-actions .is-destructive').unbind('click').on('click', function (event) {
306 + var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
307 + var thelabel = thefield.find('input[name=pmpro_userfields_field_label]').val();
308 + var answer;
309 + if (thelabel.length > 0) {
310 + answer = window.confirm('Delete the "' + thelabel + '" field?');
311 + } else {
312 + answer = window.confirm('Delete this unlabeled field?');
313 + }
314 + if (answer) {
315 + thefield.remove();
316 + pmpro_userfields_made_a_change();
317 + }
318 + });
319 +
320 + // Toggle groups.
321 + jQuery('button.pmpro_userfield-group-buttons-button-toggle-group, div.pmpro_userfield-group-header h3').unbind('click').on('click', function (event) {
322 + event.preventDefault();
323 +
324 + // Ignore if the text field was clicked.
325 + if (jQuery(event.target).prop('nodeName') === 'INPUT') {
326 + return;
327 + }
328 +
329 + // Find the toggle button and open or close.
330 + let thebutton = jQuery(event.target).parents('.pmpro_userfield-group').find('button.pmpro_userfield-group-buttons-button-toggle-group');
331 + let buttonicon = thebutton.children('.dashicons');
332 + let groupheader = thebutton.closest('.pmpro_userfield-group-header');
333 + let groupinside = groupheader.siblings('.pmpro_userfield-inside');
334 +
335 + if (buttonicon.hasClass('dashicons-arrow-up')) {
336 + // closing
337 + buttonicon.removeClass('dashicons-arrow-up');
338 + buttonicon.addClass('dashicons-arrow-down');
339 + groupinside.slideUp();
340 + } else {
341 + // opening
342 + buttonicon.removeClass('dashicons-arrow-down');
343 + buttonicon.addClass('dashicons-arrow-up');
344 + groupinside.slideDown();
345 + }
346 + });
347 +
348 + // Move group up.
349 + jQuery('.pmpro_userfield-group-buttons-button-move-up').unbind('click').on('click', function (event) {
350 + var thegroup = jQuery(this).closest('.pmpro_userfield-group');
351 + var thegroupprev = thegroup.prev('.pmpro_userfield-group');
352 + if (thegroupprev.length > 0) {
353 + thegroup.insertBefore(thegroupprev);
354 + pmpro_userfields_made_a_change();
355 + }
356 + });
357 +
358 + // Move group down.
359 + jQuery('.pmpro_userfield-group-buttons-button-move-down').unbind('click').on('click', function (event) {
360 + var thegroup = jQuery(this).closest('.pmpro_userfield-group');
361 + var thegroupnext = thegroup.next('.pmpro_userfield-group');
362 + if (thegroupnext.length > 0) {
363 + thegroup.insertAfter(thegroupnext);
364 + pmpro_userfields_made_a_change();
365 + }
366 + });
367 +
368 + // Open field.
369 + jQuery('a.edit-field').unbind('click').on('click', function (event) {
370 + var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
371 + var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
372 +
373 + fieldcontainer.removeClass('pmpro_userfield-group-field-collapse');
374 + fieldcontainer.addClass('pmpro_userfield-group-field-expand');
375 + fieldsettings.find('select[name=pmpro_userfields_field_type]').change();
376 + fieldsettings.show();
377 + });
378 +
379 + // Close field.
380 + jQuery('button.pmpro_userfields_close_field').unbind('click').on('click', function (event) {
381 + event.preventDefault();
382 + var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
383 + var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
384 + var fieldheading = fieldsettings.prev();
385 + // Update label, name, and type.
386 + fieldheading.find('span.pmpro_userfield-label').html(fieldsettings.find('input[name=pmpro_userfields_field_label]').val().replace(/(<([^>]+)>)/gi, ''));
387 + fieldheading.find('li.pmpro_userfield-group-column-name').html(fieldsettings.find('input[name=pmpro_userfields_field_name]').val());
388 + fieldheading.find('li.pmpro_userfield-group-column-type').html(fieldsettings.find('select[name=pmpro_userfields_field_type]').val());
389 +
390 + // Toggle
391 + fieldcontainer.removeClass('pmpro_userfield-group-field-expand');
392 + fieldcontainer.addClass('pmpro_userfield-group-field-collapse');
393 + fieldsettings.hide();
394 + });
395 +
396 + // Move field up.
397 + jQuery('.pmpro_userfield-field-buttons-button-move-up').unbind('click').on('click', function (event) {
398 + var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
399 + var thefieldprev = thefield.prev('.pmpro_userfield-group-field');
400 + if (thefieldprev.length > 0) {
401 + thefield.insertBefore(thefieldprev);
402 + pmpro_userfields_made_a_change();
403 + }
404 + });
405 +
406 + // Move field down.
407 + jQuery('.pmpro_userfield-field-buttons-button-move-down').unbind('click').on('click', function (event) {
408 + var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
409 + var thefieldnext = thefield.next('.pmpro_userfield-group-field');
410 + if (thefieldnext.length > 0) {
411 + thefield.insertAfter(thefieldnext);
412 + pmpro_userfields_made_a_change();
413 + }
414 + });
415 +
416 + // Duplicate field.
417 + jQuery('a.duplicate-field').unbind('click').on('click', function (event) {
418 + var thefield = jQuery(this).closest('.pmpro_userfield-group-field');
419 + thefield.clone(true).insertAfter(thefield); // clone( true ) to clone event handlers.
420 + pmpro_userfields_made_a_change();
421 + });
422 +
423 + // Toggle required at checkout field settings based on group settings.
424 + jQuery('select[name="pmpro_userfields_group_checkout"]').unbind('change').on('change', function () {
425 + var groupContainer = jQuery(this).closest('.pmpro_userfield-inside');
426 + var fieldSettings = groupContainer.find('.pmpro_userfield-group-fields');
427 + var requiredFields = fieldSettings.find('#pmpro_userfield-field-setting_required');
428 +
429 + // Toggle visibility based on group setting.
430 + if (jQuery(this).val() === 'yes') {
431 + requiredFields.show();
432 + } else {
433 + requiredFields.hide();
434 + }
435 + }).trigger('change');
436 +
437 + // Toggle field settings based on type.
438 + jQuery('select[name=pmpro_userfields_field_type]').on('change', function (event) {
439 + var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
440 + var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
441 + var fieldtype = jQuery(this).val();
442 +
443 + var fieldoptions = fieldsettings.find('#pmpro_userfield-field-setting_options');
444 + var fieldfiles = fieldsettings.find('#pmpro_userfield-row-settings_files');
445 + var fielddefault = fieldsettings.find('#pmpro_userfield-field-setting_default');
446 +
447 + // Hide all the field settings.
448 + fieldoptions.hide();
449 + fieldfiles.hide();
450 + fielddefault.hide();
451 +
452 + // Show the option field if needed.
453 + var optiontypes = ['checkbox_grouped', 'radio', 'select', 'select2', 'multiselect'];
454 + if (jQuery.inArray(fieldtype, optiontypes) > -1) {
455 + fieldoptions.show();
456 + }
457 +
458 + // Show the file field options if needed.
459 + if (fieldtype === 'file') {
460 + fieldfiles.show();
461 + }
462 +
463 + // Show the default field if needed.
464 + var defaulttypes = ['text', 'textarea', 'checkbox', 'radio', 'select', 'date', 'readonly', 'hidden', 'number'];
465 + if (jQuery.inArray(fieldtype, defaulttypes) > -1) {
466 + fielddefault.show();
467 + }
468 + });
469 +
470 + // Suggest name after leaving label field.
471 + jQuery('input[name=pmpro_userfields_field_label]').on('focusout', function (event) {
472 + var fieldcontainer = jQuery(this).parents('.pmpro_userfield-group-field');
473 + var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
474 + var fieldname = fieldsettings.find('input[name=pmpro_userfields_field_name]');
475 + if (!fieldname.val()) {
476 + fieldname.val(jQuery(this).val().toLowerCase().replace(/[^a-z0-9]/gi, '_').replace(/(^\_+|\_+$)/mg, ''));
477 + }
478 + });
479 +
480 + // If we change a field, mark it as changed.
481 + jQuery('.pmpro_userfield-group input, .pmpro_userfield-group textarea, .pmpro_userfield-group select').on('change', function (event) {
482 + pmpro_userfields_made_a_change();
483 + });
484 +
485 + // Save User Field Settings
486 + jQuery('#pmpro_userfields_savesettings').unbind('click').on('click', function (event) {
487 + ///event.preventDefault();
488 + // We have saved, so we no longer need to warn user if they try to navigate away.
489 + window.onbeforeunload = null;
490 +
491 + let field_groups = [];
492 + let group_names = [];
493 + let default_group_name = 'More Information';
494 +
495 + jQuery('.pmpro_userfield-group').each(function (index, value) {
496 + let group_name = jQuery(this).find('input[name=pmpro_userfields_group_name]').val();
497 +
498 + // Make sure name is not blank.
499 + if (group_name.length === 0) {
500 + group_name = default_group_name;
501 + }
502 + // Make sure name is unique.
503 + let count = 1;
504 + while (group_names.includes(group_name)) {
505 + count++;
506 + group_name = group_name.replace(/\(0-9*\)/, '');
507 + group_name = group_name + ' (' + String(count) + ')';
508 + }
509 + group_names.push(group_name);
510 +
511 + let group_checkout = jQuery(this).find('select[name=pmpro_userfields_group_checkout]').val();
512 + let group_profile = jQuery(this).find('select[name=pmpro_userfields_group_profile]').val();
513 + let group_description = jQuery(this).find('textarea[name=pmpro_userfields_group_description]').val();
514 +
515 + // Get level ids.
516 + let group_levels = [];
517 + jQuery(this).find('input[name="pmpro_userfields_group_membership[]"]:checked').each(function () {
518 + group_levels.push(parseInt(jQuery(this).attr('id').replace('pmpro_userfields_group_membership_', '')));
519 + });
520 +
521 + // Get fields.
522 + let group_fields = [];
523 + jQuery(this).find('div.pmpro_userfield-group-fields div.pmpro_userfield-field-settings').each(function () {
524 + let field_label = jQuery(this).find('input[name=pmpro_userfields_field_label]').val();
525 + let field_name = jQuery(this).find('input[name=pmpro_userfields_field_name]').val();
526 + let field_type = jQuery(this).find('select[name=pmpro_userfields_field_type]').val();
527 + let field_required = jQuery(this).find('select[name=pmpro_userfields_field_required]').val();
528 + let field_readonly = jQuery(this).find('select[name=pmpro_userfields_field_readonly]').val();
529 + let field_profile = jQuery(this).find('select[name=pmpro_userfields_field_profile]').val();
530 + let field_wrapper_class = jQuery(this).find('input[name=pmpro_userfields_field_class]').val();
531 + let field_element_class = jQuery(this).find('input[name=pmpro_userfields_field_divclass]').val();
532 + let field_hint = jQuery(this).find('textarea[name=pmpro_userfields_field_hint]').val();
533 + let field_options = jQuery(this).find('textarea[name=pmpro_userfields_field_options]').val();
534 + let field_allowed_file_types = jQuery(this).find('input[name=pmpro_userfields_field_allowed_file_types]').val();
535 + let field_max_file_size = jQuery(this).find('input[name=pmpro_userfields_field_max_file_size]').val();
536 + let field_default = jQuery(this).find('input[name=pmpro_userfields_field_default]').val();
537 +
538 + // Get level ids.
539 + let field_levels = [];
540 + jQuery(this).find('input[name="pmpro_userfields_field_levels[]"]:checked').each(function () {
541 + field_levels.push(parseInt(jQuery(this).attr('id').replace('pmpro_userfields_field_levels_', '')));
542 + });
543 +
544 + let field = {
545 + 'label': field_label,
546 + 'name': field_name,
547 + 'type': field_type,
548 + 'required': field_required,
549 + 'readonly': field_readonly,
550 + 'levels': field_levels,
551 + 'profile': field_profile,
552 + 'wrapper_class': field_wrapper_class,
553 + 'element_class': field_element_class,
554 + 'hint': field_hint,
555 + 'options': field_options,
556 + 'allowed_file_types': field_allowed_file_types,
557 + 'max_file_size': field_max_file_size,
558 + 'default': field_default
559 + };
560 +
561 + // Add to array. (Only if it has a label or name.)
562 + if (field.label.length > 0 || field.name.length > 0) {
563 + group_fields.push(field);
564 + }
565 + });
566 +
567 + // Set up the field group object.
568 + let field_group = {
569 + 'name': group_name,
570 + 'checkout': group_checkout,
571 + 'profile': group_profile,
572 + 'description': group_description,
573 + 'levels': group_levels,
574 + 'fields': group_fields
575 + };
576 +
577 + // Add to array.
578 + field_groups.push(field_group);
579 + });
580 +
581 + // console.log( field_groups );
582 + jQuery('#pmpro_user_fields_settings').val(JSON.stringify(field_groups));
583 +
584 + return true;
585 + });
586 + }
587 +
588 + function pmpro_stripe_get_secretkey() {
589 + // We can't do the webhook calls with the Connect keys anyway,
590 + // so we just look for the legacy key here.
591 + if (jQuery('#stripe_secretkey').val().length > 0) {
592 + return jQuery('#stripe_secretkey').val();
593 + } else {
594 + return '';
595 + }
596 + }
597 +
598 + // EMAIL TEMPLATES.
599 + jQuery(document).ready(function ($) {
600 +
601 + /* Variables */
602 + $template = $('#edit').val();
603 +
604 + $("#pmpro_submit_template_data").click(function () {
605 + pmpro_save_template()
606 + });
607 +
608 + $("#pmpro_reset_template_data").click(function () {
609 + pmpro_reset_template();
610 + });
611 +
612 + $("#pmpro_email_template_disable").click(function (e) {
613 + pmpro_disable_template();
614 + });
615 +
616 + $("#send_test_email").click(function (e) {
617 + pmpro_save_template().done(setTimeout(function () { pmpro_send_test_email(); }, '1000'));
618 + });
619 +
620 + function pmpro_save_template() {
621 +
622 + $("#pmpro_submit_template_data").attr("disabled", true);
623 + $(".status").hide();
624 + // console.log(template);
625 +
626 + $data = {
627 + template: $template,
628 + subject: $("#pmpro_email_template_subject").val(),
629 + body: $("#pmpro_email_template_body").val(),
630 + action: 'pmpro_email_templates_save_template_data',
631 + security: $('input[name=security]').val()
632 + };
633 + $.post(ajaxurl, $data, function (response) {
634 + if (response != 0) {
635 + $(".status_message_wrapper").addClass('updated');
636 + }
637 + else {
638 + $(".status_message_wrapper").addClass("error");
639 + }
640 + $("#pmpro_submit_template_data").attr("disabled", false);
641 + $(".status_message").html(response);
642 + $(".status_message").show();
643 + $('html, body').animate({ scrollTop : 0 }, 'fast');
644 + });
645 +
646 + return $.Deferred().resolve();
647 + }
648 +
649 + function pmpro_reset_template() {
650 +
651 + var r = confirm('Are you sure? Your current template settings will be deleted permanently.');
652 +
653 + if (!r) return false;
654 +
655 + $data = {
656 + template: $template,
657 + action: 'pmpro_email_templates_reset_template_data',
658 + security: $('input[name=security]').val()
659 + };
660 + $.post(ajaxurl, $data, function (response) {
661 + var template_data = $.parseJSON(response);
662 + $('#pmpro_email_template_subject').val(template_data['subject']);
663 + $('#pmpro_email_template_body').val(template_data['body']);
664 + $(".status_message_wrapper").addClass('updated');
665 + $(".status_message").html('Template Reset');
666 + $(".status_message").show();
667 + $('html, body').animate({ scrollTop : 0 }, 'fast');
668 + });
669 +
670 + return true;
671 + }
672 +
673 + function pmpro_disable_template() {
674 +
675 + //update wp_options
676 + data = {
677 + template: $template,
678 + action: 'pmpro_email_templates_disable_template',
679 + disabled: $("#pmpro_email_template_disable").is(":checked"),
680 + security: $('input[name=security]').val()
681 + };
682 +
683 + $.post(ajaxurl, data, function (response) {
684 +
685 + response = JSON.parse(response);
686 +
687 + //failure
688 + if (response['result'] == false) {
689 + $(".status_message_wrapper").addClass("error");
690 + $(".status_message").show().text("There was an error updating your template settings.");
691 + }
692 + else {
693 + if (response['status'] == 'true') {
694 + $(".status_message_wrapper").addClass("updated");
695 + $(".status_message").show().text("Template Disabled");
696 + $(".pmpro_tag-success").addClass("pmpro_tag-alert");
697 + $(".pmpro_tag-success").removeClass("pmpro_tag-success");
698 + $(".pmpro_tag-alert").text("Disabled");
699 + }
700 + else {
701 + $(".status_message_wrapper").addClass("updated");
702 + $(".status_message").show().text("Template Enabled");
703 + $(".pmpro_tag-alert").addClass("pmpro_tag-success");
704 + $(".pmpro_tag-alert").removeClass("pmpro_tag-alert");
705 + $(".pmpro_tag-success").text("Enabled");
706 + }
707 + }
708 +
709 + $('html, body').animate({ scrollTop : 0 }, 'fast');
710 +
711 + disabled = response['status'];
712 +
713 + pmpro_toggle_form_disabled(disabled);
714 + });
715 + }
716 +
717 + function pmpro_send_test_email() {
718 +
719 + data = {
720 + template: $template,
721 + email: $("#test_email_address").val(),
722 + action: 'pmpro_email_templates_send_test',
723 + security: $('input[name=security]').val()
724 + };
725 +
726 + $.post(ajaxurl, data, function (success) {
727 +
728 + if (success) {
729 + $(".status_message_wrapper").addClass("updated").removeClass("error");
730 + $(".status_message").show().text("Test email sent successfully.");
731 + }
732 + else {
733 + $(".status_message_wrapper").addClass("error").removeClass("updated");
734 + $(".status_message").show().text("Test email failed.");
735 + }
736 +
737 + })
738 + }
739 +
740 + function pmpro_toggle_form_disabled(disabled) {
741 + if (disabled == 'true') {
742 + $("#pmpro_email_template_disable").prop('checked', true);
743 + $("#pmpro_email_template_body").attr('readonly', 'readonly').attr('disabled', 'disabled');
744 + $("#pmpro_email_template_subject").attr('readonly', 'readonly').attr('disabled', 'disabled');
745 + }
746 + else {
747 + $("#pmpro_email_template_disable").prop('checked', false);
748 + $("#pmpro_email_template_body").removeAttr('readonly', 'readonly').removeAttr('disabled', 'disabled');
749 + $("#pmpro_email_template_subject").removeAttr('readonly', 'readonly').removeAttr('disabled', 'disabled');
750 + }
751 +
752 + }
753 +
754 + });
755 +
756 + // Design Settings.
757 + jQuery(document).ready(function () {
758 + // Preview color changes by updating the #pmpro_global_style_colors inline styles.
759 + jQuery('.pmpro_color_picker').on('change', function () {
760 + var baseColor = jQuery('#pmpro_base_color').val();
761 + var contrastColor = jQuery('#pmpro_contrast_color').val();
762 + var accentColor = jQuery('#pmpro_accent_color').val();
763 +
764 + jQuery('#pmpro_global_style_colors').html(':root { --pmpro--color--base: ' + baseColor + '; --pmpro--color--contrast: ' + contrastColor + '; --pmpro--color--accent: ' + accentColor + '; }');
765 + });
766 + });
767 +
768 + // Add Ons Page Code.
769 + jQuery(document).ready(function () {
770 +
771 + // If we're on the add ons admin page
772 + if (jQuery('#pmpro-admin-add-ons-list').length) {
773 +
774 + // Scoped helper object for Add Ons page (keeps readability while avoiding duplication).
775 + var pmproAddOnsHelpers = {
776 + progressText: {
777 + 'activate': 'Activating...',
778 + 'install': 'Installing...',
779 + 'update': 'Updating...',
780 + 'deactivate': 'Deactivating...',
781 + 'delete': 'Deleting...'
782 + },
783 + failText: {
784 + 'activate': 'Could Not Activate.',
785 + 'install': 'Could Not Install.',
786 + 'update': 'Could Not Update.',
787 + 'deactivate': 'Could Not Deactivate.',
788 + 'delete': 'Could Not Delete.'
789 + },
790 + recountFilters: function(){
791 + var activeCount = jQuery('.add-on-container.add-on-active').length;
792 + var inactiveCount = jQuery('.add-on-container.add-on-inactive').length;
793 + var updateCount = jQuery('.add-on-container.add-on-needs-update').length;
794 + function setCount($link, count, hide){
795 + if(!$link.length){return;}
796 + var baseLabel = $link.data('baseLabel');
797 + if(!baseLabel){
798 + baseLabel = jQuery.trim($link.text()).replace(/\s*\(\d+\)$/,'');
799 + $link.data('baseLabel', baseLabel);
800 + }
801 + $link.text(count>0? baseLabel+' ('+count+')': baseLabel);
802 + if(hide){ $link.closest('li').toggle(count>0); }
803 + }
804 + // Hide tabs whose count is zero for all three: active, inactive, update.
805 + setCount(jQuery('.filter-links a[data-view="active"]'), activeCount, true);
806 + setCount(jQuery('.filter-links a[data-view="inactive"]'), inactiveCount, true);
807 + setCount(jQuery('.filter-links a[data-view="update"]'), updateCount, true);
808 + // If current link becomes hidden, switch to All.
809 + var $currentLink = jQuery('.filter-links a.current');
810 + if ($currentLink.length && !$currentLink.closest('li').is(':visible')) {
811 + jQuery('.filter-links a[data-view="all"]').trigger('click');
812 + } else if (window.location.hash) {
813 + var hashView = window.location.hash.replace('#','');
814 + var $hashLink = jQuery('.filter-links a[data-view="' + hashView + '"]');
815 + if ($hashLink.length && !$hashLink.closest('li').is(':visible')) {
816 + jQuery('.filter-links a[data-view="all"]').trigger('click');
817 + }
818 + }
819 + },
820 + applyCurrentFilter: function(){
821 + var $current = jQuery('.filter-links a.current');
822 + if($current.length){ $current.trigger('click'); }
823 + },
824 + // Ensure the actions dropdown exists and reflects current status (installed states only).
825 + buildOrUpdateMenu: function(container, status, plugin_file, nonce){
826 + var $details = container.find('> .add-on-item > .details');
827 + if(!$details.length){ return; }
828 + var $btn = $details.children('.dropdown-arrow');
829 + var $menu = $details.children('.pmpro-add-on-actions-menu');
830 + // Only show dropdown for installed plugins (active/inactive).
831 + if(status !== 'active' && status !== 'inactive'){
832 + $btn.remove();
833 + $menu.remove();
834 + return;
835 + }
836 + if(!$btn.length){
837 + $btn = jQuery(
838 + '<button type="button" class="dropdown-arrow" aria-haspopup="true" aria-expanded="false">\n'
839 + + '\t<span class="screen-reader-text">Toggle actions menu</span>\n'
840 + + '\t<span class="dashicons dashicons-ellipsis"></span>\n'
841 + + '</button>'
842 + );
843 + $details.prepend($btn);
844 + }
845 + if(!$menu.length){
846 + $menu = jQuery(
847 + '<div class="pmpro-add-on-actions-menu" role="menu" aria-hidden="true">\n'
848 + + '\t<ul></ul>\n'
849 + + '</div>'
850 + );
851 + $btn.after($menu);
852 + }
853 + // Build menu items
854 + var $ul = $menu.children('ul');
855 + $ul.empty();
856 + // First item: Activate or Deactivate
857 + var firstAction = (status === 'inactive') ? 'activate' : 'deactivate';
858 + var firstLabel = (status === 'inactive') ? 'Activate' : 'Deactivate';
859 + $ul.append(
860 + '<li>'
861 + + '\t<button type="button" role="menuitem" class="pmproAddOnActionButton action-' + firstAction + '">' + firstLabel + '</button>'
862 + + '\t<input type="hidden" name="pmproAddOnAdminAction" value="' + firstAction + '" />'
863 + + '\t<input type="hidden" name="pmproAddOnAdminTarget" value="' + plugin_file + '" />'
864 + + '\t<input type="hidden" name="pmproAddOnAdminNonce" value="' + nonce + '" />'
865 + + '</li>'
866 + );
867 + // Divider + Uninstall
868 + $ul.append(
869 + '<li>'
870 + + '\t<button type="button" role="menuitem" class="pmproAddOnActionButton action-uninstall is-destructive">Uninstall</button>'
871 + + '\t<input type="hidden" name="pmproAddOnAdminAction" value="delete" />'
872 + + '\t<input type="hidden" name="pmproAddOnAdminTarget" value="' + plugin_file + '" />'
873 + + '\t<input type="hidden" name="pmproAddOnAdminNonce" value="' + nonce + '" />'
874 + + '</li>'
875 + );
876 + }
877 + };
878 +
879 + // Hide the license banner.
880 + jQuery('.pmproPopupCloseButton, .pmproPopupCompleteButton').click(function (e) {
881 + e.preventDefault();
882 + jQuery('.pmpro-popup-overlay').hide();
883 + });
884 +
885 + // Hide the popup banner if "ESC" is pressed.
886 + jQuery(document).keyup(function (e) {
887 + if (e.key === 'Escape') {
888 + jQuery('.pmpro-popup-overlay').hide();
889 + }
890 + });
891 +
892 + jQuery('#pmpro-admin-add-ons-list').on('click', '.pmproAddOnActionButton', function (e) {
893 + e.preventDefault();
894 +
895 + var button = jQuery(this);
896 + var container = button.closest('.add-on-container');
897 +
898 + // Make sure we only run once.
899 + if (button.hasClass('disabled')) {
900 + return;
901 + }
902 + button.addClass('disabled');
903 +
904 + // Pull the action that we are performing on this button.
905 + var action = button.siblings('input[name="pmproAddOnAdminAction"]').val();
906 +
907 + if ('license' === action) {
908 + // Get the add on name and the user's current license type and show banner.
909 + document.getElementById('addon-name').innerHTML = button.siblings('input[name="pmproAddOnAdminName"]').val();
910 + document.getElementById('addon-license').innerHTML = button.siblings('input[name="pmproAddOnAdminLicense"]').val();
911 + jQuery('.pmpro-popup-overlay').show();
912 + button.removeClass('disabled');
913 + return false;
914 + }
915 +
916 + // Remove checkmark
917 + button.removeClass('checkmarked');
918 +
919 + // Update button text (progress state)
920 + if (!pmproAddOnsHelpers.progressText[action]) {
921 + button.removeClass('disabled');
922 + return;
923 + }
924 + button.text(pmproAddOnsHelpers.progressText[action]);
925 +
926 + // Build AJAX payload for new class endpoints
927 + var target = button.siblings('input[name="pmproAddOnAdminTarget"]').val();
928 + var nonce = button.siblings('input[name="pmproAddOnAdminNonce"]').val();
929 + var ajaxAction = null;
930 + if (action === 'install') ajaxAction = 'pmpro_addon_install';
931 + if (action === 'update') ajaxAction = 'pmpro_addon_update';
932 + if (action === 'activate') ajaxAction = 'pmpro_addon_activate';
933 + if (action === 'deactivate') ajaxAction = 'pmpro_addon_deactivate';
934 + if (action === 'delete') ajaxAction = 'pmpro_addon_delete';
935 +
936 + // Send AJAX request
937 + jQuery.post(ajaxurl, {
938 + action: ajaxAction,
939 + nonce: nonce,
940 + target: target,
941 + slug: (action === 'install' ? target : ''),
942 + }).done(function(resp){
943 + if (!resp || !resp.success) {
944 + var msg = (resp && resp.data && resp.data.message) ? resp.data.message : 'Action failed.';
945 + // Filesystem credentials needed
946 + if (resp && resp.data && resp.data.code === 'pmpro_fs_credentials') {
947 + button.text('Credentials required...');
948 + if (window.wp && wp.updates && wp.updates.maybeRequestFilesystemCredentials) {
949 + wp.updates.maybeRequestFilesystemCredentials({});
950 + }
951 + } else {
952 + button.text(msg);
953 + }
954 + button.removeClass('disabled');
955 + return;
956 + }
957 +
958 + var plugin_file = (resp && resp.data && resp.data.plugin_file) ? resp.data.plugin_file : null;
959 + var slug = container.attr('id');
960 + if(!plugin_file && slug){ plugin_file = slug + '/' + slug + '.php'; }
961 + var mainButton = container.find('.action-button > .pmproAddOnActionButton');
962 + var mainActionInput = mainButton.siblings('input[name="pmproAddOnAdminAction"]');
963 + var mainTargetInput = mainButton.siblings('input[name="pmproAddOnAdminTarget"]');
964 + var statusLabel = container.find('.add-on-status strong');
965 + var dropdownBtn = container.find('.details > .dropdown-arrow');
966 + var dropdownMenu = container.find('.pmpro-add-on-actions-menu');
967 + var firstMenuBtn = dropdownMenu.find('button.pmproAddOnActionButton').first();
968 + var firstMenuActionInput = firstMenuBtn.siblings('input[name="pmproAddOnAdminAction"]');
969 +
970 + function setStatus(newStatus, statusText){
971 + container.removeClass('add-on-active add-on-inactive add-on-uninstalled');
972 + if(newStatus){ container.addClass('add-on-' + newStatus); }
973 + if(statusLabel.length){
974 + statusLabel.removeClass(function(i,c){ return (c.match(/status-\S+/g)||[]).join(' '); });
975 + statusLabel.attr('class','status-' + newStatus).text(statusText);
976 + }
977 + // Update data-search-view tokens
978 + var viewAttr = container.data('search-view');
979 + if(viewAttr){
980 + var parts = viewAttr.split(' ').filter(function(p){ return ['active','inactive','update'].indexOf(p) === -1; });
981 + if(newStatus === 'active') parts.push('active');
982 + if(newStatus === 'inactive') parts.push('inactive');
983 + if(container.hasClass('add-on-needs-update')) parts.push('update');
984 + var newView = parts.filter(function(v,i,a){ return a.indexOf(v)===i; }).join(' ');
985 + container.attr('data-search-view', newView);
986 + container.data('search-view', newView);
987 + }
988 + }
989 +
990 + // Handle each action result
991 + if (action === 'activate') {
992 + button.text('Activated').addClass('checkmarked');
993 + // Main button shows Active (disabled)
994 + if(mainButton.length){
995 + mainButton.text('Active').addClass('disabled').attr('disabled','disabled').attr('aria-disabled','true');
996 + mainActionInput.val('');
997 + mainTargetInput.val(plugin_file);
998 + }
999 + // Update dropdown first item to Deactivate
1000 + if(firstMenuBtn.length){
1001 + firstMenuBtn.text('Deactivate').removeClass('action-activate').addClass('action-deactivate');
1002 + firstMenuActionInput.val('deactivate');
1003 + }
1004 + setStatus('active', 'Active');
1005 + } else if (action === 'deactivate') {
1006 + button.text('Deactivated');
1007 + if(mainButton.length){
1008 + mainButton.text('Activate').removeClass('disabled').removeAttr('disabled').attr('aria-disabled','false').removeClass('checkmarked');
1009 + mainActionInput.val('activate');
1010 + mainTargetInput.val(plugin_file);
1011 + }
1012 + if(firstMenuBtn.length){
1013 + firstMenuBtn.text('Activate').removeClass('action-deactivate').addClass('action-activate');
1014 + firstMenuActionInput.val('activate');
1015 + }
1016 + setStatus('inactive', 'Inactive');
1017 + } else if (action === 'install') {
1018 + button.text('Installed');
1019 + // After install the plugin is inactive.
1020 + if(mainButton.length){
1021 + setTimeout(function(){
1022 + mainButton.text('Activate').removeClass('disabled checkmarked');
1023 + mainActionInput.val('activate');
1024 + mainTargetInput.val(plugin_file);
1025 + }, 600);
1026 + }
1027 + // Ensure actions menu exists/updated now that it's installed.
1028 + pmproAddOnsHelpers.buildOrUpdateMenu(container, 'inactive', plugin_file, nonce);
1029 + setStatus('inactive', 'Inactive');
1030 + } else if (action === 'update') {
1031 + button.text('Updated').addClass('checkmarked');
1032 + container.removeClass('add-on-needs-update');
1033 + // If active keep Active label, else ensure main button is Activate
1034 + if(mainButton.length){
1035 + if(container.hasClass('add-on-active')){
1036 + mainButton.text('Active').addClass('disabled').attr('disabled','disabled').attr('aria-disabled','true');
1037 + }else{
1038 + mainButton.text('Activate').removeClass('disabled');
1039 + mainActionInput.val('activate');
1040 + mainTargetInput.val(plugin_file);
1041 + }
1042 + }
1043 + // Update search view attribute removing update token
1044 + var viewAttr2 = container.data('search-view');
1045 + if(viewAttr2){
1046 + var parts2 = viewAttr2.split(' ').filter(function(p){ return p !== 'update'; });
1047 + container.attr('data-search-view', parts2.join(' '));
1048 + container.data('search-view', parts2.join(' '));
1049 + }
1050 + } else if (action === 'delete') {
1051 + button.text('Deleted').removeClass('checkmarked');
1052 + // Switch to uninstalled state
1053 + setStatus('uninstalled', 'Not Installed');
1054 + if(mainButton.length){
1055 + setTimeout(function(){
1056 + mainButton.text('Install').removeClass('disabled checkmarked').removeAttr('disabled').attr('aria-disabled','false');
1057 + mainActionInput.val('install');
1058 + mainTargetInput.val(slug); // target is slug for install
1059 + }, 600);
1060 + }
1061 + // Remove dropdown
1062 + dropdownBtn.remove();
1063 + dropdownMenu.remove();
1064 + }
1065 +
1066 + pmproAddOnsHelpers.recountFilters();
1067 + pmproAddOnsHelpers.applyCurrentFilter();
1068 +
1069 + // Re-enable after success for possible further actions (except transient states already swapped)
1070 + setTimeout(function(){
1071 + button.removeClass('disabled');
1072 + }, 400);
1073 + }).fail(function(){
1074 + button.text(pmproAddOnsHelpers.failText[action] || 'Action failed.');
1075 + button.removeClass('disabled').removeClass('checkmarked');
1076 + });
1077 + });
1078 + }
1079 + });
1080 +
1081 + // Add On Action Dropdown (toggle + accessibility)
1082 + jQuery(document).ready(function(){
1083 + // If we're on the add ons admin page
1084 + if (jQuery('#pmpro-admin-add-ons-list').length) {
1085 +
1086 + var $doc = jQuery(document);
1087 +
1088 + function closeAllAddonMenus(except){
1089 + jQuery('#pmpro-admin-add-ons-list .add-on-item .dropdown-arrow').attr('aria-expanded','false');
1090 + jQuery('#pmpro-admin-add-ons-list .add-on-item .pmpro-add-on-actions-menu').attr('aria-hidden','true');
1091 + jQuery('#pmpro-admin-add-ons-list .add-on-item').removeClass('is-open');
1092 + if (except) {
1093 + except.attr('aria-expanded','true')
1094 + .closest('.add-on-item').addClass('is-open')
1095 + .find('.pmpro-add-on-actions-menu').attr('aria-hidden','false');
1096 + }
1097 + }
1098 +
1099 + $doc.on('click', '#pmpro-admin-add-ons-list .add-on-item .dropdown-arrow', function(e){
1100 + e.preventDefault();
1101 + var $btn = jQuery(this);
1102 + var isOpen = $btn.attr('aria-expanded') === 'true';
1103 + if (isOpen) {
1104 + closeAllAddonMenus();
1105 + } else {
1106 + closeAllAddonMenus($btn);
1107 + // Focus first actionable item for keyboard users
1108 + setTimeout(function(){
1109 + var $first = $btn.next('.pmpro-add-on-actions-menu').find('button:not([disabled])').first();
1110 + if ($first.length) { $first.trigger('focus'); }
1111 + }, 15);
1112 + }
1113 + });
1114 +
1115 + // Keyboard navigation inside menu
1116 + $doc.on('keydown', '#pmpro-admin-add-ons-list .pmpro-add-on-actions-menu', function(e){
1117 + var $items = jQuery(this).find('button:not([disabled])');
1118 + if (!$items.length) { return; }
1119 + var idx = $items.index(document.activeElement);
1120 + if (e.key === 'ArrowDown') { e.preventDefault(); idx = (idx + 1) % $items.length; $items.eq(idx).focus(); }
1121 + else if (e.key === 'ArrowUp') { e.preventDefault(); idx = (idx - 1 + $items.length) % $items.length; $items.eq(idx).focus(); }
1122 + else if (e.key === 'Home') { e.preventDefault(); $items.eq(0).focus(); }
1123 + else if (e.key === 'End') { e.preventDefault(); $items.eq($items.length - 1).focus(); }
1124 + else if (e.key === 'Escape') { e.preventDefault(); closeAllAddonMenus(); }
1125 + });
1126 +
1127 + // Close when clicking outside
1128 + $doc.on('click', function(e){
1129 + if (!jQuery(e.target).closest('#pmpro-admin-add-ons-list .add-on-item .pmpro-add-on-actions-menu, #pmpro-admin-add-ons-list .add-on-item .dropdown-arrow').length) {
1130 + closeAllAddonMenus();
1131 + }
1132 + });
1133 +
1134 + // Close on Escape from anywhere
1135 + $doc.on('keyup', function(e){ if (e.key === 'Escape') { closeAllAddonMenus(); } });
1136 + }
1137 + });
1138 +
1139 + /**
1140 + * Add/Edit Member Page
1141 + */
1142 + window.addEventListener("DOMContentLoaded", () => {
1143 + const tabs = document.querySelectorAll('#pmpro-edit-user-div [role="tab"]');
1144 + const tabList = document.querySelector('#pmpro-edit-user-div [role="tablist"]');
1145 + const inputs = document.querySelectorAll('#pmpro-edit-user-div input, #pmpro-edit-user-div textarea, #pmpro-edit-user-div select');
1146 +
1147 + if ( tabs && tabList ) {
1148 + // Track whether an input has been changed.
1149 + let inputChanged = false;
1150 + inputs.forEach((input) => {
1151 + input.addEventListener('change', function(e) {
1152 + inputChanged = true;
1153 + });
1154 + });
1155 +
1156 + // Add a click event handler to each tab
1157 + tabs.forEach((tab) => {
1158 + tab.addEventListener("click", function (e) {
1159 + if ( pmpro_changeTabs(e, inputChanged ) ) {
1160 + // If we changed tabs, reset the inputChanged flag.
1161 + inputChanged = false;
1162 +
1163 + // Hide the PMPro message.
1164 + const pmproMessage = document.querySelector('#pmpro_message');
1165 + if ( pmproMessage ) {
1166 + pmproMessage.style.display = 'none';
1167 + }
1168 + }
1169 + });
1170 + });
1171 +
1172 + // Enable arrow navigation between tabs in the tab list
1173 + let tabFocus = 0;
1174 + tabList.addEventListener("keydown", (e) => {
1175 + // Move Down
1176 + if (e.key === "ArrowDown" || e.key === "ArrowUp") {
1177 + tabs[tabFocus].setAttribute("tabindex", -1);
1178 + if (e.key === "ArrowDown") {
1179 + tabFocus++;
1180 + // If we're at the end, go to the start
1181 + if (tabFocus >= tabs.length) {
1182 + tabFocus = 0;
1183 + }
1184 + // Move Up
1185 + } else if (e.key === "ArrowUp") {
1186 + tabFocus--;
1187 + // If we're at the start, move to the end
1188 + if (tabFocus < 0) {
1189 + tabFocus = tabs.length - 1;
1190 + }
1191 + }
1192 +
1193 + tabs[tabFocus].setAttribute("tabindex", 0);
1194 + tabs[tabFocus].focus();
1195 + }
1196 + });
1197 +
1198 + // Enable the button to show more tabs.
1199 + document.addEventListener('click', function(e) {
1200 + const moreTabsToggle = e.target.closest('[role="showmore"]');
1201 + if (moreTabsToggle) {
1202 + e.preventDefault();
1203 + const parent = moreTabsToggle.parentNode;
1204 + const grandparent = parent.parentNode;
1205 + grandparent.querySelectorAll('[role="tab"]').forEach((t) => t.style.display = 'block');
1206 + parent.style.display = 'none';
1207 + }
1208 + });
1209 +
1210 + // If the visible panel's corresponding tab is hidden, show all tabs.
1211 + const visiblePanel = document.querySelector('#pmpro-edit-user-div [role="tabpanel"]:not([hidden])');
1212 + if ( visiblePanel ) {
1213 + const visibleTab = document.querySelector(`[aria-controls="${visiblePanel.id}"]`);
1214 + if ( visibleTab.style.display === 'none' ) {
1215 + const moreTabsToggle = document.querySelector('[role="showmore"]');
1216 + moreTabsToggle.click();
1217 + }
1218 + }
1219 +
1220 + }
1221 +
1222 + });
1223 +
1224 + function pmpro_changeTabs( e, inputChanged ) {
1225 + e.preventDefault();
1226 +
1227 + if ( inputChanged ) {
1228 + const answer = window.confirm('You have unsaved changes. Are you sure you want to switch tabs?');
1229 + if ( ! answer ) {
1230 + return false;
1231 + }
1232 + }
1233 +
1234 + const target = e.target;
1235 + const parent = target.parentNode;
1236 + const grandparent = parent.parentNode;
1237 +
1238 + // Remove all current selected tabs
1239 + parent
1240 + .querySelectorAll('[aria-selected="true"]')
1241 + .forEach((t) => t.setAttribute("aria-selected", false));
1242 +
1243 + // Set this tab as selected
1244 + target.setAttribute("aria-selected", true);
1245 +
1246 + // Hide all tab panels
1247 + grandparent
1248 + .querySelectorAll('[role="tabpanel"]')
1249 + .forEach((p) => p.setAttribute("hidden", true));
1250 +
1251 + // Show the selected panel
1252 + grandparent.parentNode
1253 + .querySelector(`#${target.getAttribute("aria-controls")}`)
1254 + .removeAttribute("hidden");
1255 +
1256 + // Update the URL to include the panel URL in the pmpro_member_edit_panel attribute.
1257 + const fullPanelName = target.getAttribute('aria-controls');
1258 + // Need to convert pmpro-member-edit-xyz-panel to xyz.
1259 + const panelSlug = fullPanelName.replace(/^pmpro-member-edit-/, '').replace(/-panel$/, '');
1260 + const url = new URL(window.location.href);
1261 + url.searchParams.set('pmpro_member_edit_panel', panelSlug);
1262 + window.history.pushState({}, '', url);
1263 +
1264 + return true;
1265 + }
1266 +
1267 + /**
1268 + * Edit Order Page
1269 + */
1270 + jQuery(document).ready(function () {
1271 + jQuery('.pmpro_admin-pmpro-orders select#membership_id').select2();
1272 + });
1273 +
1274 + /**
1275 + * Report Widgets - Collapsed Row Toggles
1276 + */
1277 + jQuery(document).ready(function () {
1278 + jQuery('.pmpro_report_th').on('click',function(event) {
1279 + //prevent form submit onclick
1280 + event.preventDefault();
1281 +
1282 + //toggle sub rows
1283 + jQuery(this).closest('tbody').find('.pmpro_report_tr_sub').toggle();
1284 +
1285 + //change arrow
1286 + if(jQuery(this).hasClass('pmpro_report_th_closed')) {
1287 + jQuery(this).removeClass('pmpro_report_th_closed');
1288 + jQuery(this).addClass('pmpro_report_th_opened');
1289 + } else {
1290 + jQuery(this).removeClass('pmpro_report_th_opened');
1291 + jQuery(this).addClass('pmpro_report_th_closed');
1292 + }
1293 + });
1294 + });