1/** 2 * Freemius checkout, opened over the page. 3 * 4 * The pricing page has had this since the plan grid was built, but every other 5 * buy button on the site â product pages, the sticky mobile bar, the closing 6 * CTA band â was a plain link that threw the visitor into a new tab. This 7 * makes those behave the same way: the checkout opens in a modal over the 8 * page, and the product stays behind it. 9 * 10 * WHY THE LINK IS STILL A LINK 11 * ---------------------------- 12 * The markup stays an <a href> pointing at the hosted checkout, and this file 13 * only intercepts the click. So the button works with JavaScript off, works if 14 * checkout.js is blocked, works on middle-click and "open in new tab", and 15 * search engines still see a real destination. Nothing here is load-bearing â 16 * it is an upgrade on something that already worked. 17 * 18 * A button opts in by carrying data-tsm-checkout with the module ID, plus 19 * data-tsm-public. Without a public key checkout.js can only log an error, so 20 * such a link is left alone and opens the hosted page as before. 21 * 22 * Shares no state with pricing.js; both are safe on the same page, and the 23 * modal is Freemius' own so there is no second implementation to maintain. 24 */ 25( function () { 26 'use strict'; 27 28 var loading = null; 29 30 /** Load Freemius' checkout.js once, on first use rather than on page load. */ 31 function loadCheckout() { 32 if ( window.FS && window.FS.Checkout ) { 33 return Promise.resolve(); 34 } 35 36 if ( loading ) { 37 return loading; 38 } 39 40 loading = new Promise( function ( resolve, reject ) { 41 var s = document.createElement( 'script' ); 42 s.src = 'https://checkout.freemius.com/checkout.js'; 43 s.onload = resolve; 44 s.onerror = reject; 45 document.head.appendChild( s ); 46 } ); 47 48 return loading; 49 } 50 51 document.addEventListener( 'click', function ( e ) { 52 var el = e.target.closest( '[data-tsm-checkout]' ); 53 54 if ( ! el ) { 55 return; 56 } 57 58 // Let the browser do its normal thing for anything that is not a plain 59 // left click: modified clicks and middle clicks mean "new tab", and 60 // taking those over would be rude. 61 if ( e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey ) { 62 return; 63 } 64 65 var module = el.dataset.tsmCheckout; 66 var pub = el.dataset.tsmPublic; 67 68 // No key, no modal â the href still points at the hosted checkout. 69 if ( ! module || ! pub ) { 70 return; 71 } 72 73 e.preventDefault(); 74 75 var options = { 76 plugin_id: module, 77 public_key: pub 78 }; 79 80 if ( el.dataset.tsmPlanId ) { 81 options.plan_id = el.dataset.tsmPlanId; 82 } 83 84 if ( el.dataset.tsmCycle ) { 85 options.billing_cycle = el.dataset.tsmCycle; 86 } 87 88 if ( el.dataset.tsmCoupon ) { 89 options.coupon = el.dataset.tsmCoupon; 90 } 91 92 el.setAttribute( 'aria-busy', 'true' ); 93 94 function done() { 95 el.removeAttribute( 'aria-busy' ); 96 } 97 98 loadCheckout().then( function () { 99 window.FS.Checkout.configure( options ).open( { 100 purchaseCompleted: done, 101 cancel: done 102 } ); 103 } ).catch( function () { 104 // Blocked, offline, or an ad-blocker ate it: fall back to the 105 // hosted page rather than leaving a dead button. 106 done(); 107 108 if ( el.href ) { 109 window.open( el.href, '_blank', 'noopener' ); 110 } 111 } ); 112 } ); 113}() );
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.