1(function ($) { 2 'use strict'; 3 4 $(function () { 5 var gatingData = window.OPI_AUTH_ACCESS_ARTICLE || {}; 6 var isArticleGated = String(gatingData.is_article_gated) === 'true'; 7 var modalData = gatingData.modal || {}; 8 9 var $continueBtn = $('[data-continue-reading]').first(); 10 if ($continueBtn.length) { 11 $('[id$="_Article_300x250"], [id*="_Article_300x250"]').each(function () { 12 var isBeforeContinue = !!(this.compareDocumentPosition($continueBtn[0]) & Node.DOCUMENT_POSITION_FOLLOWING); 13 if (isBeforeContinue) { 14 $(this).css('display', 'none'); 15 } 16 }); 17 } 18 19 var lock = { 20 on: function () { 21 if (!document.body.classList.contains('opi-paywall-locked')) { 22 document.body.classList.add('opi-paywall-locked'); 23 } 24 document.body.style.overflow = 'hidden'; 25 }, 26 off: function () { 27 document.body.classList.remove('opi-paywall-locked'); 28 if (!document.body.classList.contains('opi-auth-locked')) { 29 document.body.style.overflow = ''; 30 } 31 } 32 }; 33 34 function one(selector) { 35 var $all = $(selector); 36 if ($all.length > 1) { 37 $all.slice(1).remove(); 38 $all = $all.eq(0); 39 } 40 return $all; 41 } 42 43 function ensureScaffold() {
44 var $overlay = one('[data-opi-paywall-overlay]'); 45 var $wrapper = one('[data-opi-paywall-wrapper]'); 46 47 if (!$overlay.length) { 48 $overlay = $( 49 '<div data-opi-paywall-overlay class="fixed inset-0 bg-black/50 backdrop-blur-sm opacity-0 transition-opacity duration-200 ease-out z-[9998] pointer-events-none" style="display:none;"></div>' 50 ).appendTo('body'); 51 } 52 if (!$wrapper.length) { 53 $wrapper = $( 54 '<div data-opi-paywall-wrapper class="fixed inset-0 z-[9999] hidden overflow-y-auto flex items-center justify-center p-6" style="visibility:hidden;"></div>' 55 ).appendTo('body'); 56 } 57 return { $overlay: $overlay, $wrapper: $wrapper }; 58 } 59 60 function showOverlay($overlay) { 61 $overlay.css('display', 'block'); 62 if ($overlay[0]) { 63 $overlay[0].offsetHeight; 64 } 65 $overlay.removeClass('pointer-events-none opacity-0') 66 .addClass('opacity-100') 67 .css('pointer-events', 'auto'); 68 } 69 70 function hideOverlay($overlay) { 71 $overlay.removeClass('opacity-100').addClass('opacity-0').css('pointer-events', 'none'); 72 setTimeout(function () { 73 $overlay.css('display', 'none'); 74 }, 200); 75 } 76 77 function hardHideWrapper($wrapper) { 78 $wrapper.addClass('hidden').removeClass('flex').css({ display: 'none', visibility: 'hidden' }); 79 } 80 81 function safeOpiCall(methodName) { 82 try { 83 return !!(window.OPI && typeof window.OPI[methodName] === 'function' && window.OPI[methodName]()); 84 } catch (err) { 85 return false; 86 } 87 } 88
89 function appendRedirectUrl(url) { 90 if (!url || !window.location || !window.location.href) { 91 return url; 92 } 93 return url + (url.indexOf('?') !== -1 ? '&' : '?') + 'redirectURL=' + encodeURIComponent(window.location.href); 94 } 95 96 function getEncryptedCustomerId() { 97 var id = ''; 98 99 if (modalData.encrypted_customer_id) { 100 id = modalData.encrypted_customer_id; 101 } 102 103 if (!id) { 104 try { 105 var access = window.OPI_AUTH_ACCESS || {}; 106 id = access.encrypted_customer_id || ''; 107 } catch (err) {} 108 } 109 110 if (!id) { 111 try { 112 var authData = window.OPI_AUTH_DATA || {}; 113 if (authData.user && authData.user.data) { 114 id = authData.user.data.encrypted_customer_id || ''; 115 } 116 } catch (err) {} 117 } 118 119 if (!id) { 120 try { 121 if (window.OPI && typeof window.OPI.getUserField === 'function') { 122 id = window.OPI.getUserField('encrypted_customer_id') || ''; 123 } 124 } catch (err) {} 125 } 126 127 if (!id) { 128 try { 129 var cookies = document.cookie.split(';'); 130 for (var i = 0; i < cookies.length; i++) { 131 var item = cookies[i].trim(); 132 if (item.indexOf('opi_user=') === 0) { 133 var raw = item.substring('opi_user='.length); 134 var cookieData; 135 try { 136 cookieData = JSON.parse(decodeURIComponent(raw)); 137 } catch (parseErr) { 138 cookieData = JSON.parse(raw); 139 } 140 if (cookieData && cookieData.encrypted_customer_id) { 141 id = cookieData.encrypted_customer_id; 142 break; 143 } 144 } 145 } 146 } catch (err) {} 147 } 148 149 return id || ''; 150 } 151 152 function applyEncryptedCustomerId(url) { 153 if (!url) { 154 return url; 155 } 156 var encryptedCustomerId = getEncryptedCustomerId(); 157 if (!encryptedCustomerId) { 158 return url; 159 } 160 return String(url) 161 .replace(/\{encrypted_customer_id\}/g, encryptedCustomerId) 162 .replace(/%7Bencrypted_customer_id%7D/gi, encryptedCustomerId); 163 } 164 165 function buildRenewLink() { 166 var renewLink = modalData.renew_link || ''; 167 if (!renewLink) { 168 return ''; 169 } 170 return appendRedirectUrl(applyEncryptedCustomerId(renewLink)); 171 } 172 173 function markup() { 174 var title = modalData.title || 'Unlock this content'; 175 var description = modalData.description || 'Sign in or register to continue reading.'; 176 var registerLink = appendRedirectUrl(modalData.register_link || ''); 177 var loginLink = modalData.login_link || '/sso/login'; 178 var isLoggedIn = safeOpiCall('isLoggedIn'); 179 var hasAccess = safeOpiCall('isStaff') || safeOpiCall('canViewDigital'); 180 var showRenewMembership = isLoggedIn && !hasAccess; 181 var primaryHref = showRenewMembership ? (buildRenewLink() || registerLink || loginLink) : registerLink; 182 var primaryLabel = showRenewMembership ? 'Renew Membership' : (modalData.register_button_text || 'Register Now'); 183 var primaryCta = primaryHref ? '<a href="' + primaryHref + '" class="w-full inline-flex items-center justify-center rounded-md border border-transparent px-4 py-2.5 text-base font-semibold text-white bg-primary hover:bg-primary-75 mb-3">' + primaryLabel + '</a>' : ''; 184 var loginPromptHtml = showRenewMembership ? '' : '<button type="button" data-opi-paywall-login class="text-sm text-gray-600 hover:text-primary hover:underline bg-transparent border-0 cursor-pointer p-0">Already a member/subscriber? Sign in</button>'; 185 186 return '' + 187 '<div id="opi-paywall-modal" data-opi-paywall-modal class="relative w-full max-w-sm rounded-xl border border-[#
187E5E5E5] bg-white overflow-visible px-6 pt-5 pb-6 flex-shrink-0 my-auto" role="dialog" aria-modal="true" aria-labelledby="opi-paywall-title">' + 188 '<button type="button" data-opi-paywall-close class="absolute top-1.5 right-1.5 z-10 inline-flex items-center justify-center rounded-md p-1.5 text-black/50 hover:text-black/70 hover:bg-black/5 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 cursor-pointer" aria-label="Close paywall modal">' + 189 '<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 pointer-events-none" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">' + 190 '<path fill-rule="evenodd" d="M10 8.586l4.95-4.95a1 1 0 111.414 1.415L11.414 10l4.95 4.95a1 1 0 01-1.415 1.414L10 11.414l-4.95 4.95a1 1 0 01-1.414-1.415L8.586 10l-4.95-4.95A1 1 0 115.05 3.636L10 8.586z" clip-rule="evenodd"/>' + 191 '</svg>' + 192 '</button>' + 193 '<div class="flex flex-col items-center justify-center text-center">' + 194 '<h2 id="opi-paywall-title" class="text-xl lg:text-2xl font-bold text-primary mt-0 mb-2 pr-1">' + title + '</h2>' + 195 '<p class="text-black/70 text-sm lg:text-base mb-4">' + description + '</p>' + 196 primaryCta + 197 loginPromptHtml + 198 '</div>' + 199 '</div>'; 200 } 201 202 function closePaywall() {
203 var $overlay = $('[data-opi-paywall-overlay]'); 204 var $wrapper = $('[data-opi-paywall-wrapper]'); 205 206 $('#opi-paywall-modal').remove(); 207 hideOverlay($overlay); 208 hardHideWrapper($wrapper); 209 lock.off(); 210 } 211 212 function unlockContent() { 213 lock.off(); 214 $('#opi_gating_part_two_content').removeClass('hidden').css('display', ''); 215 $('[data-continue-reading]').addClass('hidden').attr('aria-hidden', 'true'); 216 closePaywall(); 217 } 218 219 function openPaywall() { 220 var s = ensureScaffold(); 221 var $overlay = s.$overlay; 222 var $wrapper = s.$wrapper; 223 224 $('#opi-paywall-modal').remove(); 225 226 $wrapper.append(markup()) 227 .removeClass('hidden').addClass('flex') 228 .css({ display: 'flex', visibility: 'visible' }); 229 230 showOverlay($overlay); 231 lock.on(); 232 233 $('#opi-paywall-modal [data-opi-paywall-close]').trigger('focus'); 234 } 235 236 function continueReadingLogic() { 237 if (!isArticleGated) { 238 unlockContent(); 239 return; 240 } 241 242 try { 243 if (!window.OPI) { 244 openPaywall(); 245 return; 246 } 247 248 var isLoggedIn = safeOpiCall('isLoggedIn'); 249 var canViewDigital = safeOpiCall('canViewDigital'); 250 251 if (isLoggedIn && canViewDigital) { 252 unlockContent(); 253 try { 254 var live = document.querySelector('[aria-live]'); 255 if (live) { 256 live.textContent = 'Full article unlocked.'; 257 } 258 } catch (announceError) { 259 console.log('Live region announcement failed:', announceError); 260 } 261 } else { 262 openPaywall(); 263 } 264 } catch (err) { 265 console.log('Error during access check:', err); 266 openPaywall(); 267 } 268 } 269 270 $(document) 271 .off('click.opiPaywall', '[data-continue-reading]') 272 .on('click.opiPaywall', '[data-continue-reading]', function (e) { 273 e.preventDefault(); 274 continueReadingLogic(); 275 }); 276 277 $(document) 278 .off('click.opiPaywall', '#opi-paywall-modal [data-opi-paywall-close]') 279 .on('click.opiPaywall', '#opi-paywall-modal [data-opi-paywall-close]', function (e) { 280 e.preventDefault(); 281 closePaywall(); 282 }); 283 284 $(document) 285 .off('mousedown.opiPaywall touchstart.opiPaywall', '[data-opi-paywall-wrapper]') 286 .on('mousedown.opiPaywall touchstart.opiPaywall', '[data-opi-paywall-wrapper]', function (e) { 287 if (e.target === this && $('#opi-paywall-modal').length) { 288 closePaywall(); 289 } 290 }); 291 292 $(document) 293 .off('keydown.opiPaywall') 294 .on('keydown.opiPaywall', function (e) { 295 if ((e.key === 'Escape' || e.keyCode === 27) && $('#opi-paywall-modal').length) { 296 e.preventDefault(); 297 closePaywall(); 298 } 299 }); 300 301 $(document) 302 .off('click.opiPaywall', '#opi-paywall-modal [data-opi-paywall-login]') 303 .on('click.opiPaywall', '#opi-paywall-modal [data-opi-paywall-login]', function (e) { 304 e.preventDefault(); 305 closePaywall(); 306 // Use direct API to open login modal without custserv mode 307 if (window.opiAuthModal && typeof window.opiAuthModal.open === 'function') { 308 window.opiAuthModal.open(); 309 } 310 }); 311 }); 312})(window.jQuery || jQuery);
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.