1jQuery(document).ready(function ($) { 2 // keep track of prior active element 3 let priorFocus; 4 5 // Add all our events here 6 $(document).on("click", ".mepr-profile-details__button", openModal); 7 $(document).on("click", ".mepr_modal", closeModal); 8 $(document).on("click", ".mepr_modal__close", { force: true }, closeModal); 9 $(document).on('submit', '.mepr_modal_form', saveChanges); 10 $(document).on("add-disabled-attr", disableElements) 11 $(document).on("remove-disabled-attr", reEnableElements) 12 $(document).on("click", "#load-more-subscriptions", loadMoreSubscriptions) 13 $(document).on("click", "#load-more-payments", loadMorePayments) 14 15 /** 16 * Opens Modal Window 17 * @param {Object} event object. 18 */ 19 function openModal(event) { 20 var $modal = $("#mepr-account-modal"); 21 priorFocus = document.activeElement; 22 23 $modal.show(); 24 var fieldName = $(this).data('name'); 25 26 // get the current row. 27 if ('billing_address' == fieldName) { 28 var $currentRow = $modal.find($("input[id^='mepr-address'], select[id^='mepr-address']")).closest('.mp-form-row'); 29 $modal.find('#mp-address-group-label').show() 30 } else if ('name' == fieldName) { 31 var $currentRow = $modal.find($("input[id^='user_first_name'], select[id^='user_last_name']")).closest('.mp-form-row'); 32 } else { 33 var $currentRow = $modal.find('#' + fieldName).closest('.mp-form-row'); 34 } 35 36 // add diabled class to all form elements except those of current row. 37 // this will prevent JS errors (eg ...is not focusable) when submitting form. 38 $modal.find('.mp-form-row') 39 .not($currentRow) 40 .find('input, textarea, button, select') 41 .addClass('--disabled') 42 .trigger('add-disabled-attr'); 43 44 $currentRow.show(); 45 46 // handle a11y focus events 47 focusModal($modal); 48 49 // close modal on ESC key 50 $(document).on('keyup', function(event) { 51 const key = event.key || event.keyCode; 52 if (key === 'Escape' || key === 'Esc' || key === 27) { 53 $('.mepr_modal__close').trigger('click'); 54 } 55 }); 56 } 57 58 /** 59 * Closes Modal Window 60 * @param {Object} event object. 61 */ 62 function closeModal(event) { 63 var $modal = $("#mepr-account-modal"); 64 65 var forceDelete = event.data != undefined && 'force' in event.data; 66 if (!event.target.closest('.mepr_modal__box') || forceDelete) { 67 // select last focused element 68 if (priorFocus) { 69 priorFocus.focus(); 70 } 71 // get the current row. 72 var $currentRow = $modal.find('.mp-form-row:visible'); 73 74 // remove diabled attr from elements with --disabled class 75 $modal.find('.mp-form-row') 76 .not($currentRow) 77 .find('input, textarea, button, select') 78 .removeClass('--disabled') 79 .trigger('remove-disabled-attr'); 80 81 // hide modal and its form rows 82 $modal.hide(); 83 $modal.find('.mp-form-row').hide(); 84 $modal.find('#mp-address-group-label').hide() 85 86 // clear errors 87 $modal.find('.mepr_pro_error').addClass('hidden') 88 $modal.find('.mepr_pro_error ul').empty() 89 } 90 91 } 92 93 function focusModal(element) { 94 const focusableEls = element.find('input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled])'); 95 const closeButton = element.find('.mepr_modal__close'); 96 const firstFocusableEl = focusableEls.first().focus(); 97 const KEYCODE_TAB = 9; 98
99 firstFocusableEl.focus(); 100 101 element.on('keydown', function(e) { 102 const isTabOrSpacePressed = (e.key === 'Tab' || e.keyCode === KEYCODE_TAB || e.code === 'Space' || e.keyCode === 32); 103 104 if (!isTabOrSpacePressed) { 105 return; 106 } 107 108 if (e.shiftKey) { // shift + tab 109 if (document.activeElement === firstFocusableEl.get(0)) { 110 closeButton.get(0).focus(); 111 e.preventDefault(); 112 } 113 } else { // tab 114 if (document.activeElement === closeButton.get(0)) { 115 firstFocusableEl.focus(); 116 e.preventDefault(); 117 } 118 } 119 }); 120 } 121 122 // Saves our Changes 123 function saveChanges(e) { 124 e.preventDefault(); 125 126 var $form = $(this); 127 var formData = new FormData(this); 128 formData.append("action", "save_profile_changes"); 129 formData.append("nonce", MeprAccount.nonce); 130 131 // Let's add checkboxes, whether checked or unchecked 132 for (var i = 0; i < this.elements.length; i++) { 133 var e = this.elements[i]; 134 if (!e.disabled && e.type == 'checkbox') { 135 var val = e.checked ? 'on' : ''; 136 formData.append(e.name, val); 137 } 138 } 139 140 // Loop through each field and validate if it's required. 141 $.each($form.find('.mepr-form-input:visible'), function(i,obj) { 142 if ($(obj).attr('required') !== undefined) { 143 $(obj).removeClass('invalid'); 144 var notBlank = mpValidateFieldNotBlank($(obj)); 145 mpToggleFieldValidation($(obj), notBlank); 146 } 147 }); 148 149 // Validation failed? Bailout. 150 if (0 < $form.find('.invalid').length) { 151 return; 152 } 153 154 _fetch(formData).done(function (response) { 155 $form.find('.mepr_pro_error ul').empty() 156 157 if(false === response.success){ 158 $form.find('.mepr_pro_error').removeClass('hidden'); 159 for (let i = 0; i < response.data.length; i++){ 160 var list = document.createElement('li'); 161 list.innerText=response.data[i]; 162 $form.find('.mepr_pro_error ul').append(list); 163 } 164 } else { 165 location.reload(); 166 } 167 }); 168 } 169 170 171 172 /** 173 * Adds disabled attr to all elements with the --disabled class 174 * @param {Event} e the event object. 175 */ 176 function disableElements(e) { 177 $(e.target).prop('disabled', true); 178 }; 179 180 /** 181 * Removes disabled attr to all elements with the --disabled class 182 * @param {Event} e the event object. 183 */ 184 function reEnableElements(e) { 185 $(e.target).prop('disabled', false); 186 }; 187 188 function loadMoreSubscriptions() { 189 var count = $(this).data('count'); 190 var $spinner = $(this).parent().find('.mepr-account-meta__spinner'); 191 $spinner.show(); 192 $(this).hide(); 193 194 var formData = new FormData(); 195 formData.append("count", count); 196 formData.append("action", "load_more_subscriptions"); 197 formData.append("account_url", MeprAccount.account_url); 198 formData.append("nonce", MeprAccount.nonce); 199 200 _fetch(formData) 201 .done(function (response) { 202 $('#mepr-account-content').html(response.data); 203 204 $('.mepr-open-resume-confirm, .mepr-open-cancel-confirm').magnificPopup({ 205 type: 'inline', 206 closeBtnInside: false 207 }); 208 209 $('.mepr-open-upgrade-popup').magnificPopup({ 210 type: 'inline', 211 closeBtnInside: false 212 }); 213 214 createPopperInstances(); 215 216 $spinner.hide(); 217 }); 218 } 219 220 function loadMorePayments() { 221 var count = $(this).data('count'); 222 var $spinner = $(this).parent().find('.mepr-account-meta__spinner'); 223 $spinner.show(); 224 $(this).hide(); 225 226 var formData = new FormData(); 227 formData.append("count", count); 228 formData.append("action", "load_more_payments"); 229 formData.append("nonce", MeprAccount.nonce); 230 231 _fetch(formData) 232 .done(function (response) { 233 $('#mepr-account-content').html(response.data); 234 createPopperInstances(); 235 $spinner.hide(); 236 }); 237 } 238 239 /** 240 * A wrapper to perform AJAX requests. 241 * Although named 'fetch', this is XHR not Fetch API 242 * @param {Object} data Data to pass to AJAX. 243 * @returns Promise 244 */ 245 function _fetch(data = {}) { 246 args = { 247 type: 'POST', 248 url: MeprAccount.ajax_url, 249 dataType: 'json', 250 data: data, 251 cache: false, 252 processData: false, 253 contentType: false, 254 }; 255 256 return $.ajax(args); 257 } 258 259 // Tooltip 260 var popperInstances = []; 261 262 createPopperInstances(); 263 264 $(document).on('click', handlePopperEvents); 265 $(document).on('keyup', handlePopperEvents); 266 267 function handlePopperEvents(e) { 268 // Only run on click or keyup 269 if (e.type !== 'click' && (e.type !== 'keyup')) { 270 return; 271 } 272 273 // On keyup only run on Escape 274 if (e.type === 'keyup' && e.key !== 'Escape') { 275 return; 276 } 277 278 var $trigger = $('.mepr-tooltip-trigger'); 279 var $popover = $('.mepr-tooltip-content'); 280 var $target = $(e.target); 281 282 // Change target to parent if child element was clicked 283 if(!$target.is($trigger) && $target.closest($trigger)){ 284 $target = $target.closest('.mepr-tooltip-trigger'); 285 } 286 287 if ($target.is($popover)) { 288 return; 289 } 290 291 if (e.type === 'keyup' && e.key === 'Escape') { 292 hidePopperAll($popover); 293 return; 294 } 295 296 if ($target.is($trigger)) { 297 var index = $trigger.index($target.get(0)); 298 var instance = popperInstances[index]; 299 var popover = $target.parent().find('.mepr-tooltip-content').get(0); 300 301 if (!instance) return; 302 303 togglePopper(instance, popover); 304 } else { 305 hidePopperAll($popover) 306 } 307 } 308 309 function createPopperInstances() { 310 destroyPopperInstances(); 311 $('.mepr-tooltip-trigger').each(function (index) { 312 var $trigger = $(this); 313 var $content = $(this).parent().find('.mepr-tooltip-content'); 314 var PopperInstance = Popper.createPopper($trigger.get(0), $content.get(0), { 315 modifiers: [ 316 { 317 name: 'offset', 318 options: { 319 offset: [0, 8], 320 }, 321 }, 322 ], 323 }); 324 325 popperInstances.push(PopperInstance); 326 }); 327 } 328 329 function destroyPopperInstances() {
330 popperInstances.forEach(function (instance) { 331 instance.destroy(); 332 }); 333 popperInstances = []; 334 } 335 336 function togglePopper(instance, tooltip) { 337 if (tooltip.hasAttribute("data-show")) { 338 hidePopper(instance, tooltip); 339 } else { 340 showPopper(instance, tooltip); 341 } 342 } 343 344 //show and create popper 345 function showPopper(instance, tooltip) { 346 tooltip.setAttribute('data-show', ''); 347 348 instance.setOptions((options) => ({ 349 ...options, 350 modifiers: [ 351 ...options.modifiers, 352 { name: 'eventListeners', enabled: true }, 353 ], 354 })); 355 356 // Update its position 357 instance.update(); 358 } 359 360 //hide and destroy popper instance 361 function hidePopper(instance, tooltip) { 362 tooltip.removeAttribute('data-show'); 363 364 instance.setOptions((options) => ({ 365 ...options, 366 modifiers: [ 367 ...options.modifiers, 368 { name: 'eventListeners', enabled: false }, 369 ], 370 })); 371 } 372 373 //hide and destroy popper instance 374 function hidePopperAll(tooltips) { 375 tooltips.each(function (index, tooltip) { 376 tooltip.removeAttribute('data-show'); 377 }) 378 379 popperInstances.forEach(function (instance) { 380 instance.setOptions((options) => ({ 381 ...options, 382 modifiers: [ 383 ...options.modifiers, 384 { name: 'eventListeners', enabled: false }, 385 ], 386 })); 387 }) 388 } 389});
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.