1jQuery(function ($) { 2 3 $('.el_mem_checklist').mwMemberChecklist(); 4 5 $('.mw_element_item_popup .mw_element_item_title a, .mw_element_item_popup .mw_element_item_image_hover').mwElementPopup(); 6 7 $('#member_show_profile').mwMemberProfileAdmin(); 8 9 var urlParams = new URLSearchParams(window.location.search); 10 if (urlParams.get('mw_discord') === 'connect') { 11 urlParams.delete('mw_discord'); 12 var newSearch = urlParams.toString(); 13 history.replaceState(null, null, window.location.pathname + (newSearch ? '?' + newSearch : '')); 14 var $profileEl = $('#member_show_profile'); 15 if ($profileEl.length && $profileEl[0].MwMemberProfileAdmin) { 16 $profileEl[0].MwMemberProfileAdmin.openModal('integrations'); 17 } 18 } 19 20 // TODO JQMIGRATE: jQuery.hover is deprecated, use "mouseenter" and "mouseleave" events (https://stackoverflow.com/a/13004732) 21 $("#member_user_avatar").hover( 22 function () { 23 $(this).addClass('member_user_menu_open'); 24 $(this).removeClass('member_user_menu_close'); 25 }, 26 function () { 27 $(this).removeClass('member_user_menu_open'); 28 $(this).addClass('member_user_menu_close'); 29 }); 30 31 // Close member user menu when user touches a link inside the menu (mobile fix) 32 $("#member_user_menu a").on('click', function () { 33 $("#member_user_avatar").removeClass('member_user_menu_open').addClass('member_user_menu_close'); 34 }); 35 36 //news 37 $(".member_new_show_text").click(function () { 38 $(this).closest(".mw_element_item_description").find(".member_new_short").toggle(); 39 $(this).closest(".mw_element_item_description").find(".member_new_text").toggle(); 40 return false; 41 }); 42 43 mw_init_register_form('.mw_member_register_form'); 44 mw_init_login_form('.member_login_form'); 45}); 46 47function mw_init_register_form(target) { 48 jQuery(target).mwForm({ 49 onsubmit: function (self, $form) { 50 var form = $form.serialize(); 51 var loading = self.$el.find("button"); 52 loading.addClass('working'); 53 54 jQuery.post(ajaxurl, 'action=send_registration_form&' + form, function (data) { 55 56 if (data.redirect) { 57 if (data.target) { 58 window.parent.location = data.redirect; 59 } else { 60 window.location = data.redirect; 61 } 62 } 63 else { 64 self.showMessage(data); 65 loading.removeClass('working'); 66 } 67 68 }).fail(function (data) { 69 console.log(data); 70 self.showMessage({'sended': 'error', 'message': mem_front_texts.reg_nosended}); 71 loading.removeClass('working'); 72 }); 73 74 } 75 }); 76} 77 78function mw_init_login_form(target) { 79 jQuery(target).mwMemberLoginForm(); 80} 81 82function mw_init_member_checklist(target) { 83 jQuery(target).mwMemberChecklist(); 84} 85 86;(function (factory) { 87 88 if (typeof define === 'function' && define.amd) { 89 define(['jquery'], factory); 90 } else if (typeof exports !== 'undefined') { 91 module.exports = factory(require('jquery')); 92 } else { 93 factory(jQuery); 94 } 95 96})(function ($) { 97 98 // checklist 99 var MwMemberChecklist = (function (element) { 100 101 function _MwMemberChecklist(element) { 102 this.$el = $(element); 103 this.userId = this.$el.data('user_id'); 104 this.checklistId = this.$el.data('checklist_id'); 105 this.type = this.$el.data('type'); 106 var obj = this; 107 108 this.$el.find('li').click(function() { 109 110 $(this).find('.mem_checklist_checkbox').toggleClass('mem_checklist_checkbox_checked'); 111 var checkbox = $(this).find('input'); 112 113 if($(this).find('.mem_checklist_checkbox').hasClass('mem_checklist_checkbox_checked')) { 114 checkbox.attr('checked', true); 115 var checked = 1; 116 } else { 117 checkbox.attr('checked', false); 118 var checked = 0; 119 } 120 var id = checkbox.val(); 121 122 $.post(ajaxurl, { 123 "action": "mwmSaveMemberChecklist", 124 "taskId": id, 125 "checked": checked, 126 "type": obj.type, 127 "userId": obj.userId, 128 "checklistId": obj.checklistId, 129 }, function (data) { 130 //console.log(data); 131 }) 132 133 }); 134 135 } 136 137 return _MwMemberChecklist; 138 139 })(); 140 141 $.fn.mwMemberChecklist = function (options) { 142 return this.each(function (index, el) { 143 el.MwMemberChecklist = new MwMemberChecklist(el, options); 144 }); 145 }; 146 147 // login form 148 var MwMemberLoginForm = (function (element) { 149 150 function _MwMemberLoginForm(element) { 151 this.$el = $(element); 152 var obj = this; 153 154 this.$el.find('.mw_password_input_container').mwPasswordInput(); 155 156 this.$el.find('.ve_form_text').on('paste', function(e) { 157 let input = $(this); 158 e.preventDefault(); 159 let pastedText = (e.originalEvent || e).clipboardData.getData('text'); 160 let trimmedText = pastedText.trim(); 161 input.val(trimmedText); 162 }); 163 164 this.$el.find('.mw_send_two_factor_login').click(function (e) { 165 e.preventDefault(); 166 167 let $but = $(this); 168 if ($but.hasClass('working')) { 169 return false;
170 } 171 $but.addClass('working'); 172 173 let form = obj.$el.serialize(); 174 175 $.post(ajaxurl, 'action=mw_send_login_form&' + form, function (response) { 176 obj.$el.find('.mw_login_form_message_container').html(''); 177 obj.$el.find('.mw_login_code_message_container').html(''); 178 if (response.success) { 179 obj.$el.find('.mw_login_code_container').show(); 180 obj.$el.closest('.col').css('z-index', 3); 181 obj.$el.closest('.element_container').css('z-index', 3); 182 } else { 183 obj.$el.find('.mw_login_form_message_container').html(response.data.message); 184 } 185 $but.removeClass('working'); 186 }).fail(function (data) { 187 console.log(data); 188 self.showMessage({'sended': 'error', 'message': 'test'}); 189 $but.removeClass('working'); 190 }); 191 }); 192 193 this.$el.find('.mw_check_two_factor_code').click(function (e) { 194 e.preventDefault(); 195 obj.$el.find('.mw_login_code_message_container').html(''); 196 197 let $but = $(this); 198 if ($but.hasClass('working')) { 199 return false; 200 } 201 $but.addClass('working'); 202 203 let form = obj.$el.serialize(); 204 205 $.post(ajaxurl, 'action=mw_check_login_code&' + form, function (response) { 206 if (response.success) { 207 window.location.href = response.data.redirect; 208 } else { 209 if (response.data.show_login) { 210 obj.$el.find('.mw_login_code_container').hide(); 211 obj.$el.find('.mw_login_code_container input').val(''); 212 obj.$el.find('.mw_login_form_message_container').html(response.data.message); 213 } else { 214 obj.$el.find('.mw_login_code_message_container').html(response.data.message); 215 } 216 $but.removeClass('working'); 217 } 218 }).fail(function (data) { 219 console.log(data); 220 self.showMessage({'sended': 'error', 'message': 'Neznámá chyba'}); 221 $but.removeClass('working'); 222 }); 223 }); 224 225 this.$el.find('.mw_send_two_factor_code').click(function (e) { 226 e.preventDefault(); 227 obj.$el.find('.mw_login_code_message_container').html(''); 228 229 let $but = $(this); 230 if ($but.hasClass('working')) { 231 return false; 232 } 233 $but.addClass('working'); 234 235 $.post(ajaxurl, 'action=mw_send_login_code', function (response) { 236 if (response.data.show_login) { 237 obj.$el.find('.mw_login_code_container').hide(); 238 obj.$el.find('.mw_login_code_container input').val(''); 239 obj.$el.find('.mw_login_form_message_container').html(response.data.message); 240 } else { 241 obj.$el.find('.mw_login_code_message_container').html(response.data.message); 242 } 243 $but.removeClass('working'); 244 }).fail(function (data) { 245 console.log(data); 246 self.showMessage({'sended': 'error', 'message': 'Neznámá chyba'}); 247 $but.removeClass('working'); 248 }); 249 }); 250 251 this.$el.find('.mw_cancel_two_factor').click(function (e) { 252 e.preventDefault(); 253 obj.$el.find('.mw_login_code_container').hide(); 254 obj.$el.closest('.col').css('z-index', 2); 255 obj.$el.closest('.element_container').css('z-index', 2); 256 }); 257 258 this.$el.find('.mw_set_password_ajax').click(function (e) { 259 e.preventDefault(); 260 261 let $but = $(this); 262 if ($but.hasClass('working')) { 263 return false; 264 } 265 $but.addClass('working'); 266 267 let password1 = obj.$el.find('input[name="new_password"]').val(); 268 let password2 = obj.$el.find('input[name="confirm_password"]').val(); 269 let userId = obj.$el.find('input[name="user_id"]').val(); 270 let token = obj.$el.find('input[name="token"]').val(); 271 let redirectTo = obj.$el.find('input[name="redirect_after_set_password"]').val(); 272 273 $.post(ajaxurl, { 274 action: 'mw_set_password', 275 new_password: password1, 276 confirm_password: password2, 277 user_id: userId, 278 token: token, 279 redirect_to: redirectTo 280 }, function (response) { 281 282 obj.$el.find('.mw_set_password_message_container').html(''); 283 284 if (response.success) { 285 if (response.data.redirect) { 286 window.location.href = response.data.redirect; 287 } else { 288 obj.$el.find('.mw_set_password_modal').hide(); 289 obj.$el.find('.mw_set_password_modal input').val(''); 290 obj.$el.find('.mw_login_form_message_container').html(response.data.message); 291 } 292 } else { 293 obj.$el.find('.mw_set_password_message_container').html( 294 '<div class="mw_message_error">' + response.data.message + '</div>' 295 ); 296 } 297 298 $but.removeClass('working'); 299 }).fail(function (data) { 300 console.log(data); 301 $but.removeClass('working'); 302 }); 303 }); 304 305 } 306 307 return _MwMemberLoginForm; 308 309 })(); 310 311 $.fn.mwMemberLoginForm = function (options) { 312 return this.each(function (index, el) { 313 el.MwMemberLoginForm = new MwMemberLoginForm(el, options); 314 }); 315 }; 316 317 // member profile admin 318 var MwMemberProfileAdmin = (function (element) { 319 320 function _MwMemberProfileAdmin(element) { 321 this.$el = $(element); 322 323 const modalContainerId = 'mw_member_profile_container'; 324 325 // Create modal container 326 $('body').append('<div id="' + modalContainerId + '"></div>'); 327 328 const selectors = { 329 container: '#' + modalContainerId, 330 overlay: '#mw_member_profile_overlay', 331 modal: '#mw_member_profile_modal', 332 content: '#mw_member_profile_modal .mw_member_profile_content', 333 menuItem: '#mw_member_profile_modal .mw_member_profile_menu li', 334 close: '#mw_member_close_profile_modal', 335 menuContainer: '#mw_member_profile_modal .mw_member_profile_menu_container' 336 }; 337 338 this.openModal = function(section) { 339 this.createEmptyModal(); 340 this.loadModal(section || 'profile'); 341 }; 342 343 this.showLoadingOverlay = function() { 344 $('body').append('<div id="mw_loading_indicator"><div class="mw_spinner"></div></div>'); 345 }; 346 347 this.hideLoadingOverlay = function() { 348 $('#mw_loading_indicator').fadeOut(150, function() { 349 $(this).remove(); 350 }); 351 }; 352 353 this.createEmptyModal = function() { 354 $(selectors.container).empty(); 355 356 // Create basic modal structure 357 const modalHtml = ` 358 <div id="mw_member_profile_overlay" class="mw_member_profile_overlay"></div> 359 <div id="mw_member_profile_modal" class="mw_member_profile_modal"> 360 <a href="#" id="mw_member_close_profile_modal"></a> 361 <div class="mw_member_profile_wrapper"> 362 <div class="mw_member_profile_content loading"> 363 <div class="mw_member_profile_content_inner"></div> 364 </div> 365 </div> 366 </div> 367 `; 368 369 $(selectors.container).html(modalHtml); 370 371 // Disable body scroll when modal is open 372 this.scrollPosition = window.pageYOffset; 373 $('body').addClass('mw_member_modal_open').css('top', -this.scrollPosition + 'px'); 374 375 // Force browser reflow 376 $(selectors.modal)[0].offsetHeight; 377 378 requestAnimationFrame(function() { 379 $(selectors.overlay).addClass('visible'); 380 $(selectors.modal).addClass('visible'); 381 }); 382 }; 383 384 this.initializeOrdersSection = function(section) { 385 if (section !== 'orders') { 386 return; 387 } 388 389 const $content = $(selectors.content); 390 391 if (!$content[0].MwMemberOrders) { 392 $content.mwMemberOrders(); 393 } 394 }; 395 396 this.initializeIntegrationsSection = function(section) { 397 if (section !== 'integrations') { 398 return; 399 } 400 401 this.handleDiscordConnect(); 402 this.handleDiscordDisconnect(); 403 }; 404 405 this.initializeSubscriptionsSection = function(section) { 406 if (section !== 'subscriptions') { 407 return; 408 } 409 410 this.handleSubscriptionApActivate(); 411 this.handleSubscriptionApDeactivate(); 412 }; 413 414 this.handleSubscriptionApActivate = function() { 415 var self = this; 416 417 function openApPopup(uuid) { 418 var $popup = $('.mw_subscription_ap_popup'); 419 $popup.data('uuid', uuid); 420 $popup.find('.mw_subscription_ap_checkbox').prop('checked', false); 421 $popup.find('.mw_subscription_ap_confirm_enable').addClass('mw_subscription_ap_enable_disabled'); 422 $popup.fadeIn(150); 423 } 424 425 function closeApPopup() { 426 $('.mw_subscription_ap_popup').fadeOut(150); 427 } 428 429 $(document).off('click.mwAp').on('click.mwAp', '.mw_subscription_ap_activate_link', function(e) { 430 e.preventDefault(); 431 openApPopup($(this).data('subscription-uuid')); 432 }); 433 434 $(document).off('click.mwApCancel').on('click.mwApCancel', '.mw_subscription_ap_confirm_cancel', function(e) { 435 e.preventDefault(); 436 closeApPopup(); 437 }); 438 439 $(document).off('click.mwApBackdrop').on('click.mwApBackdrop', '.mw_subscription_ap_popup_backdrop', function() { 440 closeApPopup(); 441 }); 442 443 $(document).off('change.mwApCheckbox').on('change.mwApCheckbox', '.mw_subscription_ap_checkbox', function() { 444 var $confirmBtn = $('.mw_subscription_ap_popup').find('.mw_subscription_ap_confirm_enable'); 445 if ($(this).is(':checked')) { 446 $confirmBtn.removeClass('mw_subscription_ap_enable_disabled'); 447 } else { 448 $confirmBtn.addClass('mw_subscription_ap_enable_disabled'); 449 } 450 }); 451 452 $(document).off('click.mwApEnable').on('click.mwApEnable', '.mw_subscription_ap_confirm_enable', function(e) { 453 e.preventDefault(); 454 if ($(this).hasClass('mw_subscription_ap_enable_disabled')) { 455 return; 456 } 457 458 var $link = $(this); 459 var $popup = $('.mw_subscription_ap_popup'); 460 var uuid = $popup.data('uuid'); 461 462 if ($link.hasClass('working')) { 463 return; 464 } 465 $link.addClass('working'); 466 467 $.post(mwMemberProfileData.ajaxurl, { 468 action: 'mwsEnableAutomaticPayments', 469 uuid: uuid 470 }).done(function() { 471 closeApPopup(); 472 self.loadSection('subscriptions'); 473 }).fail(function() { 474 console.error('AP enable failed'); 475 }).always(function() { 476 $link.removeClass('working'); 477 }); 478 }); 479 }; 480 481 this.handleSubscriptionApDeactivate = function() { 482 var self = this; 483 484 $(document).off('click.mwApDeactivate').on('click.mwApDeactivate', '.mw_subscription_ap_deactivate_link', function(e) { 485 e.preventDefault(); 486 var $link = $(this); 487 var uuid = $link.data('subscription-uuid'); 488 489 if ($link.hasClass('working')) { 490 return; 491 } 492 $link.addClass('working'); 493 494 $.post(mwMemberProfileData.ajaxurl, { 495 action: 'mwsDisableAutomaticPayments', 496 uuid: uuid 497 }).done(function() { 498 self.loadSection('subscriptions'); 499 }).fail(function() { 500 console.error('AP disable failed'); 501 }).always(function() { 502 $link.removeClass('working'); 503 }); 504 }); 505 }; 506 507 // Load modal content via AJAX 508 this.loadModal = function(section) { 509 $.post(mwMemberProfileData.ajaxurl, { 510 action: 'mw_member_profile_get_modal', 511 section: section 512 }).done(function(response) { 513 if (response.success && response.data.html) { 514 const $wrapper = $(selectors.modal).find('.mw_member_profile_wrapper');
515 const $tempContainer = $('<div>').html(response.data.html); 516 517 $wrapper.empty(); 518 519 const $menuContainer = $tempContainer.find('.mw_member_profile_menu_container'); 520 const $contentContainer = $tempContainer.find('.mw_member_profile_content'); 521 522 // Append the extracted content to wrapper 523 if ($menuContainer.length && $contentContainer.length) { 524 $menuContainer.addClass('mw_member_fade_in'); 525 $contentContainer.addClass('mw_member_fade_in'); 526 527 $wrapper.append($menuContainer); 528 $wrapper.append($contentContainer); 529 530 // Trigger reflow to make transition work 531 $menuContainer[0].offsetHeight; 532 $contentContainer[0].offsetHeight; 533 534 $menuContainer.addClass('mw_member_fade_in_visible'); 535 $contentContainer.addClass('mw_member_fade_in_visible'); 536 } else { 537 // Fallback - just append all the HTML from response 538 const $content = $('<div>').html(response.data.html).addClass('mw_member_fade_in'); 539 $wrapper.append($content); 540 541 // Trigger reflow 542 $content[0].offsetHeight; 543 544 // Fade in 545 $content.addClass('mw_member_fade_in_visible'); 546 } 547 548 this.handleLoadingClass(false); 549 this.initializeOrdersSection(section); 550 this.initializeIntegrationsSection(section); 551 this.initializeSubscriptionsSection(section); 552 this.hideLoadingOverlay(); 553 554 // Add a small horizontal bump animation on mobile to indicate menu is scrollable 555 if (window.innerWidth <= 767) { 556 // Check if the animation has already been shown 557 if (!document.cookie.match(/mw_member_menu_bump=1/)) { 558 // Use requestAnimationFrame to ensure DOM is updated 559 requestAnimationFrame(function() { 560 const $menu = $('#mw_member_profile_modal .mw_member_profile_menu'); 561 const startPos = $menu.scrollLeft(); 562 563 // If the menu has enough width to scroll, animate a small horizontal bump 564 if ($menu[0].scrollWidth > $menu.outerWidth()) { 565 $menu.animate({ scrollLeft: startPos + 50 }, 200, function() { 566 $menu.animate({ scrollLeft: startPos }, 200); 567 }); 568 569 // Set cookie so the animation doesn't show again 570 const expiry = new Date(); 571 expiry.setFullYear(expiry.getFullYear() + 1); 572 document.cookie = 'mw_member_menu_bump=1; expires=' + expiry.toUTCString() + '; path=/'; 573 } 574 }); 575 } 576 } 577 } else { 578 console.error('Failed to load profile modal'); 579 this.hideLoadingOverlay(); 580 this.closeModal(); 581 } 582 }.bind(this)).fail(function() { 583 console.error('AJAX request failed'); 584 this.hideLoadingOverlay(); 585 this.closeModal(); 586 }.bind(this)); 587 }; 588 589 this.handleDiscordConnect = function() { 590 $(document).on('click', '.mw_integration_discord_connect_link', function (e) { 591 e.preventDefault(); 592 593 const url = $(this).data('url'); 594 const width = 600; 595 const height = 700; 596 const left = (screen.width/2)-(width/2); 597 const top = (screen.height/2)-(height/2); 598 599 const popup = window.open( 600 url, 601 "discord_oauth_popup", 602 `width=${width},height=${height},top=${top},left=${left},resizable=yes,scrollbars=yes` 603 ); 604 605 const profileEl = $('#member_show_profile')[0]; 606 const timer = setInterval(function () { 607 if (!popup || popup.closed) { 608 clearInterval(timer); 609 610 if (profileEl && profileEl.MwMemberProfileAdmin) { 611 profileEl.MwMemberProfileAdmin.loadSection('integrations'); 612 } else { 613 window.location.reload(); 614 } 615 } 616 }, 500); 617 }); 618 } 619 620 this.handleDiscordDisconnect = function() { 621 $(document).on('click', '.mw_integration_disconnect_link', function (e) { 622 e.preventDefault(); 623 624 $.post(mwMemberProfileData.ajaxurl, { 625 action: 'mw_member_profile_disconnect_discord', 626 }).done(function(response) { 627 const profileEl = $('#member_show_profile')[0]; 628 if (profileEl && profileEl.MwMemberProfileAdmin) { 629 profileEl.MwMemberProfileAdmin.loadSection('integrations'); 630 } else { 631 window.location.reload(); 632 } 633 }.bind(this)).fail(function() { 634 console.error('AJAX request failed'); 635 }.bind(this)); 636 }); 637 } 638 639 // Function to update spinner and overlay position based on scroll 640 this.updateSpinnerPosition = function() { 641 const $content = $(selectors.content); 642 643 if (!$content.hasClass('loading')) return; 644 645 const scrollTop = $content.scrollTop(); 646 const contentHeight = $content.outerHeight(); 647 const spinnerTop = scrollTop + (contentHeight / 2); 648 649 // Set spinner position (centered in visible area) 650 $content[0].style.setProperty('--mw-spinner-top', spinnerTop + 'px'); 651 652 // Set overlay position and height to cover visible area 653 $content[0].style.setProperty('--mw-overlay-top', scrollTop + 'px'); 654 $content[0].style.setProperty('--mw-overlay-height', contentHeight + 'px'); 655 }; 656 657 // Helper function to handle loading class 658 this.handleLoadingClass = function(isLoading) { 659 const $content = $(selectors.content); 660 661 if (isLoading) { 662 $content.addClass('loading'); 663 $(selectors.menuContainer).addClass('loading'); 664 this.updateSpinnerPosition(); 665 666 // Add scroll listener to handle inertia scrolling during loading 667 $content.on('scroll.loadingSpinner', this.updateSpinnerPosition.bind(this)); 668 } else { 669 $content.removeClass('loading'); 670 $(selectors.menuContainer).removeClass('loading'); 671 672 // Remove scroll listener when loading is complete 673 $content.off('scroll.loadingSpinner'); 674 } 675 }; 676 677 this.closeModal = function() {
678 const $overlay = $(selectors.overlay); 679 const $modal = $(selectors.modal); 680 const $container = $(selectors.container); 681 682 // Re-enable body scroll when modal closes 683 $('body').removeClass('mw_member_modal_open').css('top', ''); 684 window.scrollTo(0, this.scrollPosition); 685 686 // Remove visible class to trigger the transition 687 $overlay.removeClass('visible'); 688 $modal.removeClass('visible'); 689 690 // Clear hash 691 window.location.hash = ''; 692 693 // Detect when the fade-out is complete 694 $overlay.one('transitionend', function() { 695 // Remove modal content 696 $container.empty(); 697 }); 698 }; 699 700 this.setActive = function(section) { 701 // Find all menu items and remove active class 702 $(selectors.menuItem).removeClass('active'); 703 // Add active class to the current section 704 $(selectors.menuItem + '[data-section="' + section + '"]').addClass('active'); 705 }; 706 707 this.loadSection = function(section, page) { 708 this.setActive(section); 709 this.handleLoadingClass(true); 710 711 var data = { 712 action: 'mw_member_profile_get', 713 section: section 714 }; 715 716 if (page) { 717 data.page = page; 718 } 719 720 $.post(mwMemberProfileData.ajaxurl, data).done(function (resp) { 721 if (resp.success) { 722 const $newContent = $('<div>').html(resp.data.html).addClass('mw_member_fade_in'); 723 724 if (!page) { 725 $(selectors.content).scrollTop(0); 726 } 727 728 $(selectors.content).html($newContent); 729 730 // Trigger reflow 731 $newContent[0].offsetHeight; 732 733 // Apply fade-in class 734 $newContent.addClass('mw_member_fade_in_visible'); 735 this.initializeOrdersSection(section); 736 this.initializeIntegrationsSection(section); 737 this.initializeSubscriptionsSection(section); 738 739 // Scroll to top after content is loaded after changing page 740 if (page) { 741 $(selectors.content).animate({ scrollTop: 0 }, 300); 742 } 743 } else { 744 $(selectors.content).html('<p class="mw_member_error">' + (resp.data.message || 'Error') + '</p>'); 745 } 746 }.bind(this)).fail(function () { 747 $(selectors.content).html('<p class="mw_member_error">' + mwMemberProfileData.ajaxError + '</p>'); 748 }.bind(this)).always(function () { 749 this.handleLoadingClass(false); 750 }.bind(this)); 751 }; 752 753 this.displayMessage = function(container, message, isError) { 754 const messageClass = isError ? 'mw_member_error' : 'mw_member_success'; 755 const messageHtml = '<div class="' + messageClass + '">' + message + '</div>'; 756 757 container.empty(); 758 container.html(messageHtml); 759 760 const scrollPos = container.offset().top - 20; 761 const currentScroll = $(selectors.content).scrollTop(); 762 763 // Scroll if there is need to scroll up (message is above current viewport) 764 if (currentScroll > scrollPos) { 765 $(selectors.content).animate({ scrollTop: scrollPos }, 200); 766 } 767 }; 768 769 this.handleFormSubmit = function(form) { 770 const $form = $(form); 771 const $submitButton = $form.find('button[type="submit"], input[type="submit"]'); 772 773 // Blur any focused input elements 774 document.activeElement && document.activeElement.blur && document.activeElement.blur(); 775 776 // Find message container or create one if not found 777 let $messageContainer = $form.prev('.mw_member_message_container'); 778 if ($messageContainer.length === 0) { 779 $messageContainer = $form.closest('div').find('.mw_member_message_container'); 780 } 781 if ($messageContainer.length === 0) { 782 $messageContainer = $form.parent().find('.mw_member_message_container'); 783 } 784 if ($messageContainer.length === 0) {
785 $messageContainer = $('<div class="mw_member_message_container"></div>'); 786 $form.before($messageContainer); 787 } 788 789 if ($submitButton.length) { 790 $submitButton.prop('disabled', true); 791 } 792 793 this.handleLoadingClass(true); 794 795 $.ajax({ 796 url: mwMemberProfileData.ajaxurl, 797 type: 'POST', 798 data: $form.serialize() + '&action=mw_member_profile_save', 799 dataType: 'json', 800 success: function(response) { 801 let errorMessage = ''; 802 let isError = false; 803 804 // Set default values based on success/failure state 805 isError = !response.success; 806 errorMessage = isError ? mwMemberProfileData.errorSaving : mwMemberProfileData.changesSaved; 807 808 // Override with response message if available 809 if (response.data && typeof response.data.message === 'string') { 810 errorMessage = response.data.message; 811 } 812 813 // For password form, clear the fields on form submission 814 if ($form.find('input[name="user[user_pass]"]').length) { 815 $form.find('input[type="password"]').val(''); 816 } 817 818 // Handle nonce updates 819 if (response.success && response.data) { 820 // If server signals to refresh nonce (for password changes) 821 if (response.data.refresh_nonce) { 822 // Make an AJAX call to get a fresh nonce 823 $.post(mwMemberProfileData.ajaxurl, { 824 action: 'mw_member_refresh_nonce' 825 }).done(function(nonceResp) { 826 if (nonceResp.success && nonceResp.data && nonceResp.data.nonce) { 827 // Update the form with the fresh nonce 828 $form.find('input[name="mw_member_profile_save"]').val(nonceResp.data.nonce); 829 } 830 }); 831 } 832 // If nonce is directly provided in response (regular profile updates) 833 else if (response.data.nonce) { 834 $form.find('input[name="mw_member_profile_save"]').val(response.data.nonce); 835 } 836 } 837 838 this.displayMessage($messageContainer, errorMessage, isError); 839 }.bind(this), 840 error: function() { 841 this.displayMessage($messageContainer, mwMemberProfileData.communicationError, true); 842 }.bind(this), 843 complete: function() { 844 this.handleLoadingClass(false); 845 846 if ($submitButton.length) { 847 $submitButton.prop('disabled', false); 848 } 849 }.bind(this) 850 }); 851 852 return false; // prevent default form submission 853 }; 854 855 // Bindings 856 var self = this; 857 858 this.$el.on('click', function(e) { 859 e.preventDefault(); 860 self.openModal('profile'); 861 }); 862 863 $(document).on('click', selectors.menuItem + ' a', function (e) { 864 e.preventDefault(); 865 const section = $(this).parent().data('section'); 866 if (section) { 867 self.loadSection(section); 868 } 869 }); 870 871 $(document).on('click', selectors.close + ',' + selectors.overlay, function (e) { 872 e.preventDefault(); 873 self.closeModal(); 874 }); 875 876 // Intercept form submissions and handle via AJAX 877 $(document).on('submit', '.mw_member_profile_form', function(e) { 878 e.preventDefault(); 879 return self.handleFormSubmit(this); 880 }); 881 882 $(window).on('keyup', function (e) { 883 if (e.key === 'Escape') { 884 self.closeModal(); 885 } 886 }); 887 } 888 889 return _MwMemberProfileAdmin; 890 891 })(); 892 893 $.fn.mwMemberProfileAdmin = function (options) { 894 return this.each(function (index, el) { 895 el.MwMemberProfileAdmin = new MwMemberProfileAdmin(el, options); 896 }); 897 }; 898 899 // member orders 900 var MwMemberOrders = (function (element) { 901 902 function _MwMemberOrders(element) { 903 this.$el = $(element); 904 905 // Handle order details toggle 906 this.$el.on('click', '.mw_member_order_main', function(e) { 907 // Don't toggle if clicking on invoice link 908 if ($(e.target).closest('.mw_order_invoice_icon').length) { 909 return; 910 } 911 912 const $orderRow = $(this).closest('.mw_member_order_row'); 913 const $details = $orderRow.find('.mw_member_order_details'); 914 const $main = $(this); 915 916 $details.slideToggle(300); 917 $main.toggleClass('mw_toggle_group_open'); 918 }); 919 920 // Handle orders pagination 921 this.$el.on('click', '.mw_page_navigation a.page-numbers', function(e) { 922 e.preventDefault(); 923 924 // Extract page number from href like "#page-3" 925 const href = $(this).attr('href'); 926 const match = href.match(/#page-(\d+)/); 927 928 if (!match) return; 929 930 const page = parseInt(match[1], 10); 931 const $profileAdmin = $('#member_show_profile')[0]; 932 933 if ($profileAdmin && $profileAdmin.MwMemberProfileAdmin) { 934 $profileAdmin.MwMemberProfileAdmin.loadSection('orders', page); 935 } 936 }); 937 } 938 939 return _MwMemberOrders; 940 941 })(); 942 943 $.fn.mwMemberOrders = function (options) { 944 return this.each(function (index, el) { 945 el.MwMemberOrders = new MwMemberOrders(el, options); 946 }); 947 }; 948});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.