@rathnasgala/theme 2.0.15 → 2.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rathnasgala/theme",
3
- "version": "2.0.15",
3
+ "version": "2.0.17",
4
4
  "description": "Managed Gala static-site theme payload",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,7 +8,7 @@
8
8
  "url": "git+https://github.com/rathnasgala/site-template.git"
9
9
  },
10
10
  "gala": {
11
- "sourceCommit": "3c71d3fa099d04d5de82e6fadd49d202ccb614fc"
11
+ "sourceCommit": "b1016438e0838f2c17a6884e02f5070a40ebc092"
12
12
  },
13
13
  "files": [
14
14
  "payload"
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "themePackage": {
4
4
  "name": "@rathnasgala/theme",
5
- "version": "2.0.15",
5
+ "version": "2.0.17",
6
6
  "availableDesignThemes": [
7
7
  "editorial",
8
8
  "modern",
@@ -11,7 +11,7 @@
11
11
  "securityAdvisories": []
12
12
  },
13
13
  "requiredBudgets": {
14
- "managedJavaScriptBytes": 67584,
14
+ "managedJavaScriptBytes": 68608,
15
15
  "managedCssBytes": 34816
16
16
  },
17
17
  "files": {
@@ -41,7 +41,7 @@
41
41
  "src/_data/languages.js": "1358748f7fa2f74406d3295a030827d6229a53e94da72cf712e719d7a356aeac",
42
42
  "src/_data/site.js": "41e60190d22337321d480a29be9774eaa93a98b848e92b5139129ae97c44fd97",
43
43
  "src/_includes/components/ui.njk": "993ddb816a3a74f476040dc403abae3fd02896e99be480fd57177c342c8e8201",
44
- "src/_includes/layouts/base.njk": "054460a1293e55a5abc5902899ef2f7a6e256b50aa51375e8d209e2cf2ec2aeb",
44
+ "src/_includes/layouts/base.njk": "61526fd4f1614d1ca8e52115a6f9402428215e651648dc77d63559471bee763f",
45
45
  "src/_includes/layouts/post.njk": "e48e00ca916b740d95e465caae1f1efc0523056ce4bdadd2d2593b80072de530",
46
46
  "src/_includes/layouts/prism-configuration.njk": "c984441ac50465eb6ee0e050c68c054e3a0bca98960fb92fb2f5795443301594",
47
47
  "src/404.njk": "be0d44370ac5402156aaf3d32ea581057bc61ec94c1a5f92bb809733af7a8a20",
@@ -53,10 +53,10 @@
53
53
  "src/assets/engagement-comments.js": "eda0fee471c7e42ee01a25b8aa14ed6ae9690d52b3fbb34027d97534ab62998b",
54
54
  "src/assets/engagement-transport.js": "7f69815c4eb4fc0e127a5c09702da4189130d47b73b4598fce4196d7d6f5cbe8",
55
55
  "src/assets/favicon.svg": "8615e3d96fe37ae9ed14afb1886e7c0e690eef5b10be66ca91cccfd085a74bb6",
56
- "src/assets/interactions.js": "cfc67fb45fbf77dc584e0c2dd3a8de797ba6410cbe225a6e82b7c074bc832c5d",
56
+ "src/assets/interactions.js": "5703833592835b898b47618cfc0e926366d40fb45c1d0468b796b2a6c69c083e",
57
57
  "src/assets/preferences.js": "789127bee013ed6a1bbf8cefd7b9109291c16220e7a6e09314e3c93c54731d1d",
58
58
  "src/assets/prism-session.js": "1fab23725b843006c3f589af7669ef3ad6ad01f3264a3b00564e64b56738d2cd",
59
- "src/assets/reader.js": "0be5a7f7bae2c274f65e34421d74d7abcc228112fbbf49ec52e69980dad86ecd",
59
+ "src/assets/reader.js": "6b3ef09e3e1ef00cf3ddfa55872b1c434322ab12a1f0c65908e2623c13d11f1a",
60
60
  "src/assets/search.js": "df425f0239277792ad39f2138bc89cb66cc4ecda5ed59042d46abc2f05372088",
61
61
  "src/assets/theme-mode.js": "d81af8317b59f6d94dc8154c1dcba9d3e16accb37348bc3fce127712141d6c63",
62
62
  "src/assets/theme.css": "7391086efd6f61791c47bbdf3523d7452e17b1cdb1fc91339861fe2f0a2c884b",
@@ -105,7 +105,7 @@
105
105
  <dialog id="gala-account-dialog" class="gala-dialog gala-account-dialog" aria-labelledby="gala-account-title">
106
106
  <form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close account">Close</button></form>
107
107
  <h2 id="gala-account-title" class="gala-visually-hidden">Gala account</h2>
108
- <iframe data-gala-session-frame title="Gala account and sign in" loading="lazy" allow="identity-credentials-get" src="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/widget/session?siteId={{ site.site.id | escape }}"></iframe>
108
+ <iframe data-gala-session-frame title="Gala account and sign in" loading="eager" allow="identity-credentials-get" src="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/widget/session?siteId={{ site.site.id | escape }}"></iframe>
109
109
  </dialog>
110
110
  {% endif %}
111
111
  </body>
@@ -323,6 +323,60 @@ const pendingEngagementWrites = new Map();
323
323
  * and the comment they were typing keeps its text and its caret.
324
324
  */
325
325
  let pendingIntent = null;
326
+ const sessionFrame = document.querySelector('[data-gala-session-frame]');
327
+ const sessionOrigin = sessionFrame ? new URL(sessionFrame.src).origin : null;
328
+ let sessionFrameReady = false;
329
+ let pendingSessionTransferCode = null;
330
+ let sessionFrameToken = null;
331
+
332
+ function deliverSessionTransfer() {
333
+ if (!sessionFrameReady || !sessionFrame || !pendingSessionTransferCode) return;
334
+ sessionFrame.contentWindow?.postMessage({
335
+ type: 'gala-session-transfer', transferCode: pendingSessionTransferCode,
336
+ }, sessionOrigin);
337
+ pendingSessionTransferCode = null;
338
+ }
339
+
340
+ function requestSessionState() {
341
+ sessionFrame?.contentWindow?.postMessage({ type: 'gala-session-request' }, sessionOrigin);
342
+ }
343
+
344
+ if (sessionFrame) {
345
+ // If the frame already loaded, the immediate request reaches it. If it is still loading, the
346
+ // load handler repeats the request. This covers both orderings without timing assumptions.
347
+ sessionFrame.addEventListener('load', requestSessionState);
348
+ requestSessionState();
349
+ }
350
+
351
+ async function fedCmSession(mode) {
352
+ const status = document.querySelector('[data-engagement-status]');
353
+ if (!sessionFrameToken) return false;
354
+ if (!globalThis.IdentityCredential || typeof navigator.credentials?.get !== 'function') {
355
+ if (status) status.textContent = 'FedCM is not available in this browser. Use a current browser to sign in.';
356
+ return false;
357
+ }
358
+ try {
359
+ const siteId = new URL(sessionFrame.src).searchParams.get('siteId') ?? '';
360
+ const provider = {
361
+ configURL: 'https://api.gala67.com/v1/fedcm/config.json',
362
+ clientId: siteId,
363
+ params: { nonce: sessionFrameToken }
364
+ };
365
+ if (mode === 'active') provider.mode = 'active';
366
+ const credential = await navigator.credentials.get({
367
+ identity: { providers: [provider] },
368
+ mediation: mode === 'active' ? 'required' : 'silent'
369
+ });
370
+ if (typeof credential?.token !== 'string') return false;
371
+ pendingSessionTransferCode = credential.token;
372
+ deliverSessionTransfer();
373
+ return true;
374
+ } catch (error) {
375
+ if (error?.name !== 'NotAllowedError') console.error('Gala FedCM sign-in failed.', error);
376
+ if (mode === 'active' && status) status.textContent = 'Sign-in did not finish. Try again.';
377
+ return false;
378
+ }
379
+ }
326
380
 
327
381
  function requestSession(intent) {
328
382
  const field = intent.field;
@@ -334,20 +388,10 @@ function requestSession(intent) {
334
388
  draft: field ? field.value : null,
335
389
  caret: field ? field.selectionStart : null
336
390
  };
337
- // One window, not three. Asking used to open a modal, containing a frame, containing a
338
- // button, that opened a popup. The popup is the only part that has to exist, because it is
339
- // the only one running at the top level on the origin the identity providers accept.
340
- const frame = document.querySelector('[data-gala-session-frame]');
341
- const status = document.querySelector('[data-engagement-status]');
342
- if (!frame) return;
343
- const source = new URL(frame.getAttribute('src'), window.location.href);
344
- const signIn = new URL('/v1/widget/session/sign-in', source.origin);
345
- signIn.searchParams.set('siteId', source.searchParams.get('siteId') ?? '');
346
391
  if (field) field.blur();
347
- if (!window.open(signIn, 'gala-sign-in', 'popup,width=520,height=680')) {
348
- pendingIntent = null;
349
- if (status) status.textContent = 'Allow pop-ups for this site to sign in, then try again.';
350
- }
392
+ fedCmSession('active').then((started) => {
393
+ if (!started) pendingIntent = null;
394
+ });
351
395
  }
352
396
 
353
397
  /** Puts the reader back exactly where the sign-in interrupted them. */
@@ -375,38 +419,11 @@ function resumeIntent() {
375
419
  element.click();
376
420
  }
377
421
 
378
- // Signing in happens in another window, so the moment this one is focused again is the moment
379
- // the reader is back and the interrupted action can be finished.
380
- window.addEventListener('focus', () => {
381
- if (sessionUser && pendingIntent) resumeIntent();
382
- });
383
-
384
- /*
385
- * The sign-in window reports success to this page rather than to the account frame.
386
- *
387
- * It cannot reach the frame directly: a frame embedded in a publication has its storage - and its
388
- * BroadcastChannel - partitioned away from a window running at the top level on the API's origin,
389
- * so the session it wrote is invisible there. The signal carries no token; it only says a sign-in
390
- * happened, and this asks the frame to look again. Without it the frame never learns the reader
391
- * signed in, and every click asks them to sign in once more.
392
- */
393
- window.addEventListener('message', (event) => {
394
- const frame = document.querySelector('[data-gala-session-frame]');
395
- if (!frame || event.data?.type !== 'gala-session-established') return;
396
- const apiOrigin = new URL(frame.src).origin;
397
- if (event.origin !== apiOrigin || typeof event.data.transferCode !== 'string') return;
398
- frame.contentWindow?.postMessage({
399
- type: 'gala-session-transfer', transferCode: event.data.transferCode,
400
- }, apiOrigin);
401
- });
402
-
403
422
  document.querySelectorAll('[data-engagement-url]').forEach((region) => {
404
423
  refreshEngagement(region);
405
424
  recordView(region);
406
425
  });
407
426
 
408
- const sessionFrame = document.querySelector('[data-gala-session-frame]');
409
-
410
427
  function engagementErrorMessage(code) {
411
428
  if (code === 'AUTHENTICATION_REQUIRED' || code === 'INVALID_BEARER_TOKEN'
412
429
  || code === 'REAUTHENTICATION_REQUIRED') return 'Sign in again to continue.';
@@ -480,7 +497,6 @@ async function mutateEngagement(region, operation, payload) {
480
497
  }
481
498
 
482
499
  if (sessionFrame) {
483
- const sessionOrigin = new URL(sessionFrame.src).origin;
484
500
  window.addEventListener('message', (event) => {
485
501
  if (event.origin !== sessionOrigin || event.source !== sessionFrame.contentWindow) return;
486
502
  if (event.data?.type === 'gala-engagement-result') {
@@ -515,6 +531,9 @@ if (sessionFrame) {
515
531
  return;
516
532
  }
517
533
  if (event.data?.type !== 'gala-session') return;
534
+ sessionFrameReady = true;
535
+ if (typeof event.data.frameToken === 'string') sessionFrameToken = event.data.frameToken;
536
+ if (pendingSessionTransferCode) deliverSessionTransfer();
518
537
  sessionUser = event.data.user && typeof event.data.user.id === 'string' ? event.data.user : null;
519
538
  const control = document.querySelector('[data-user-control]');
520
539
  const displayName = sessionUser?.displayName;
@@ -545,5 +564,11 @@ if (sessionFrame) {
545
564
  });
546
565
  // Signed in on the back of an interrupted action: finish what they were doing.
547
566
  if (sessionUser && pendingIntent) resumeIntent();
567
+ if (!sessionUser && sessionFrameToken) fedCmSession('passive');
548
568
  });
549
569
  }
570
+
571
+ window.addEventListener('message', (event) => {
572
+ if (event.origin !== sessionOrigin || event.source !== sessionFrame?.contentWindow) return;
573
+ if (event.data?.type === 'gala-fedcm-sign-in') fedCmSession('active');
574
+ });
@@ -1,2 +1,2 @@
1
- (()=>{var b=["system","light","dark"],O="gala-color-mode";function D(){let e=document.documentElement.dataset.mode;return b.includes(e)?e:"system"}function Z(){try{let e=localStorage.getItem(O);if(b.includes(e))return e}catch{return D()}return D()}function M(e){document.documentElement.dataset.mode=e;let t=b[(b.indexOf(e)+1)%b.length];document.querySelectorAll("[data-theme-mode-toggle]").forEach(a=>{let n=a.querySelector?.("[data-theme-mode-label]");n?n.textContent=`Theme: ${e}`:a.textContent=`Theme: ${e}`,a.setAttribute("aria-label",`Color mode: ${e}. Activate for ${t}.`)})}document.addEventListener("DOMContentLoaded",()=>{M(Z()),document.querySelectorAll("[data-theme-mode-toggle]").forEach(e=>{e.addEventListener("click",()=>{let t=b[(b.indexOf(document.documentElement.dataset.mode)+1)%b.length];try{localStorage.setItem(O,t)}catch{}M(t)})})});var F="gala-language-preference";function ee(){try{return localStorage.getItem(F)}catch{return null}}function P(e,t){return[...e.options].find(a=>a.value===t)}document.addEventListener("DOMContentLoaded",()=>{let e=ee();document.querySelectorAll("[data-language-preference]").forEach(t=>{e!=null&&P(t,e)!=null&&(t.value=e),t.addEventListener("change",()=>{try{localStorage.setItem(F,t.value)}catch{}if(!t.hasAttribute("data-navigate-on-selection"))return;let a=P(t,t.value);a?.dataset.url&&window.location.assign(a.dataset.url)})})});var H="gala.prism.session.v1";document.addEventListener("click",e=>{if(e.target.closest("[data-prism-restore]")){try{sessionStorage.removeItem(H)}catch{}return}let a=e.target.closest("[data-prism-select]");if(a)try{sessionStorage.setItem(H,JSON.stringify({articleId:a.dataset.prismArticleId,language:a.dataset.prismLanguage,configurationId:a.dataset.prismConfigurationId,sourceRevisionHash:a.dataset.prismSourceHash,selectedAt:new Date().toISOString()}))}catch{}});function v(e){let t=e.closest(".gala-share"),a=t?.querySelector(".gala-share__fallback");a?.classList.add("gala-share__fallback--visible"),a?.focus(),a?.select();let n=t?.querySelector(".gala-share__status");n&&(n.textContent="Select and copy the URL shown.")}var G=document.querySelector("[data-reading-progress]"),q=document.querySelector(".gala-markdown");if(G&&q){let e=null,t=()=>{e=null;let n=q.offsetTop,s=Math.max(1,q.offsetHeight-window.innerHeight),o=Math.min(1,Math.max(0,(window.scrollY-n)/s));G.value=o},a=()=>{e==null&&(e=requestAnimationFrame(t))};addEventListener("scroll",a,{passive:!0}),addEventListener("resize",a,{passive:!0}),a()}var C=document.querySelector(".gala-toc");if(C?.tagName==="DETAILS"){let e=C.querySelector("nav"),t=[...C.querySelectorAll('a[href^="#"]')],a=t.map(d=>document.getElementById(d.hash.slice(1))).filter(Boolean),n=null,s=()=>{if(n=null,C.classList.toggle("gala-toc--floating",C.getBoundingClientRect().top<=96),!a.length)return;let d=window.innerHeight*.42,f=a[0];for(let i of a)if(i.getBoundingClientRect().top<=d)f=i;else break;let y=t.find(i=>i.hash===`#${f.id}`);for(let i of t)i===y?i.setAttribute("aria-current","location"):i.removeAttribute("aria-current");if(e&&t.length){let i=t[0].getBoundingClientRect(),r=t[t.length-1].getBoundingClientRect();C.classList.toggle("gala-toc--overflowing",r.bottom-i.top>e.clientHeight)}if(y&&e&&e.scrollHeight>e.clientHeight){let i=e.getBoundingClientRect(),r=y.getBoundingClientRect(),c=e.scrollTop+r.top-i.top-(e.clientHeight-r.height)/2;e.scrollTo({top:Math.max(0,c),behavior:"auto"})}},o=()=>{n==null&&(n=requestAnimationFrame(s))};addEventListener("scroll",o,{passive:!0}),addEventListener("resize",o,{passive:!0}),o()}var $=document.querySelector(".gala-action-rail"),j=document.querySelector("[data-action-dock]");if($&&j){let e=t=>{$.classList.toggle("gala-action-rail--integrated",t[0].isIntersecting)};new IntersectionObserver(e,{rootMargin:"0px 0px 18% 0px",threshold:0}).observe(j)}function Y(e,t){let a=t?"Unfollow article":"Follow article";e.setAttribute("aria-pressed",String(t)),e.setAttribute("aria-label",a),e.title=a;let n=e.querySelector("[data-follow-label]");n&&(n.textContent=a)}document.addEventListener("click",async e=>{if(e.target instanceof HTMLDialogElement&&e.target.open){let i=e.target.getBoundingClientRect();if(e.clientX<i.left||e.clientX>i.right||e.clientY<i.top||e.clientY>i.bottom){e.target.close();return}}let t=e.target.closest("[data-gala-embed-load]");if(t){let i=t.closest("[data-gala-embed]"),r=t.dataset.galaEmbedSrc,c=t.dataset.galaEmbedLoad;if(!i||!r||!["youtube","codepen"].includes(c))return;let u=document.createElement("iframe");u.src=r,u.title=c==="youtube"?"YouTube video":"CodePen example",u.loading="eager",u.referrerPolicy="strict-origin-when-cross-origin",u.setAttribute("sandbox","allow-forms allow-popups allow-presentation allow-same-origin allow-scripts"),u.setAttribute("allow",c==="youtube"?"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share":"fullscreen"),u.setAttribute("allowfullscreen",""),i.replaceChildren(u);return}let a=e.target.closest("[data-open-dialog]");if(a){let i=document.getElementById(a.dataset.openDialog);i instanceof HTMLDialogElement&&i.showModal();return}let n=e.target.closest("[data-reaction]");if(n){let i=n.closest("[data-engagement-url]");if(!i)return;if(!E)return R({kind:"reaction",region:i,selector:`[data-reaction="${n.dataset.reaction}"]`});let r=n.getAttribute("aria-pressed")!=="true";if(!await W(i,r?"reaction.add":"reaction.remove",{articleId:i.dataset.articleId,reaction:n.dataset.reaction}))return;n.setAttribute("aria-pressed",String(r));return}let s=e.target.closest("[data-follow-article]");if(s){let i=s.closest("[data-engagement-url]");if(!i)return;if(!E)return R({kind:"follow",region:i,selector:"[data-follow-article]"});let r=s.getAttribute("aria-pressed")!=="true";if(!await W(i,r?"follow.add":"follow.remove",{targetType:"articles",targetId:i.dataset.articleId}))return;Y(s,r);return}let o=e.target.closest("[data-copy-url]");if(o){let i=o.dataset.copyUrl;if(!window.isSecureContext||!navigator.clipboard?.writeText){v(o);return}try{await navigator.clipboard.writeText(i);let r=o.closest(".gala-share")?.querySelector(".gala-share__status");r&&(r.textContent="Link copied.")}catch{v(o)}return}let d=e.target.closest("[data-native-share]");if(d){if(navigator.share)try{await navigator.share({title:document.title,url:d.dataset.nativeShare})}catch(i){i.name!=="AbortError"&&v(d)}else v(d);return}let f=e.target.closest("[data-copy-code]");if(!f)return;let y=f.closest(".gala-code-block")?.querySelector("code");if(!(!y||!navigator.clipboard?.writeText||!window.isSecureContext))try{await navigator.clipboard.writeText(y.textContent),f.textContent="Copied"}catch{f.textContent="Select code to copy"}});var te=new Set([...document.querySelectorAll("pre code")].map(e=>e.closest("pre")).filter(Boolean));te.forEach(e=>{let t=document.createElement("div");t.className="gala-code-block",e.before(t),t.append(e);let a=document.createElement("button");a.type="button",a.dataset.copyCode="",a.textContent="Copy code",a.setAttribute("aria-label","Copy code block"),t.prepend(a)});function ae(e){return[["Reactions",Object.values(e.reactions??{}).reduce((a,n)=>a+(Number.isSafeInteger(n)?n:0),0)],["Comments",Number.isSafeInteger(e.comments?.totalCount)?e.comments.totalCount:0],["Views",Number.isSafeInteger(e.views?.count)?e.views.count:0]]}function ne(e){return e<1e3?"<1K":new Intl.NumberFormat("en",{notation:"compact",maximumFractionDigits:1}).format(e)}function re(e,t){let a=t?.data;if(!a||typeof a!="object")throw new TypeError("Engagement data is invalid");for(let[n,s]of ae(a))e.querySelectorAll(`[data-engagement-stat="${n.toLowerCase()}"]`).forEach(o=>{o.textContent=ne(s),o.closest("div")?.setAttribute("title",`${s} ${n.toLowerCase()}`)});e.querySelector("[data-engagement-snapshot]")?.remove(),e.querySelector(".gala-engagement__placeholder")?.remove()}async function x(e,t="",a=!1,n=!1){let s=e.querySelector("[data-engagement-status]"),o=!!e.querySelector("[data-gala-comments]");try{let d=new URL(e.dataset.engagementUrl);t&&d.searchParams.set("commentsCursor",t);let f=await fetch(d,{headers:{Accept:"application/json"},credentials:"omit",cache:n?"no-store":"default"});if(!f.ok)throw new Error(`Engagement returned HTTP ${f.status}`);let y=await f.json();re(e,y),s&&!o&&(s.textContent=y.errors?.length?"Some engagement data is temporarily unavailable.":"")}catch{s&&!o&&(s.textContent="Engagement is temporarily unavailable.")}}function oe(){let e=new URL(window.location.href).searchParams,t={};for(let a of["utm_source","utm_medium","utm_campaign","utm_content","utm_term"]){let n=e.get(a);n&&[...n].length<=128&&(t[a]=n)}return t}function se(e){let t=new URL(e.dataset.engagementUrl);t.pathname=t.pathname.replace(/\/engagement$/,"/views"),fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({language:document.documentElement.lang||void 0,referrer:document.referrer||void 0,campaign:oe()}),credentials:"omit",keepalive:!0}).catch(()=>{})}document.addEventListener("gala-request-sign-in",e=>{E||S||R({kind:e.detail?.kind??"comment"})});var E=null,B=null,_=null,L=new Map,S=null;function R(e){let t=e.field;S={kind:e.kind,region:e.region,selector:e.selector,draft:t?t.value:null,caret:t?t.selectionStart:null};let a=document.querySelector("[data-gala-session-frame]"),n=document.querySelector("[data-engagement-status]");if(!a)return;let s=new URL(a.getAttribute("src"),window.location.href),o=new URL("/v1/widget/session/sign-in",s.origin);o.searchParams.set("siteId",s.searchParams.get("siteId")??""),t&&t.blur(),window.open(o,"gala-sign-in","popup,width=520,height=680")||(S=null,n&&(n.textContent="Allow pop-ups for this site to sign in, then try again."))}function V(){let e=S;if(!e||!document.hasFocus())return;let t=e.region?.querySelector(e.selector);if(t){if(S=null,e.kind==="comment"){e.draft!=null&&t.value===""&&(t.value=e.draft),t.focus(),e.caret!=null&&typeof t.setSelectionRange=="function"&&t.setSelectionRange(e.caret,e.caret);return}t.click()}}window.addEventListener("focus",()=>{E&&S&&V()});window.addEventListener("message",e=>{let t=document.querySelector("[data-gala-session-frame]");if(!t||e.data?.type!=="gala-session-established")return;let a=new URL(t.src).origin;e.origin!==a||typeof e.data.transferCode!="string"||t.contentWindow?.postMessage({type:"gala-session-transfer",transferCode:e.data.transferCode},a)});document.querySelectorAll("[data-engagement-url]").forEach(e=>{x(e),se(e)});var I=document.querySelector("[data-gala-session-frame]");function Q(e){return e==="AUTHENTICATION_REQUIRED"||e==="INVALID_BEARER_TOKEN"||e==="REAUTHENTICATION_REQUIRED"?"Sign in again to continue.":e==="ENGAGEMENT_RATE_LIMITED"?"You are posting too quickly; try again shortly.":e==="CONTACT_RATE_LIMITED"?"You are sending too quickly; try again later.":e==="RESOURCE_NOT_FOUND"?"That item is no longer available.":e==="INVALID_ENGAGEMENT_WRITE"||e==="INVALID_CONTACT_SUBMISSION"||e==="INVALID_REQUEST"?"Check your entry and try again.":e==="ACCESS_DENIED"?"That action is not available for this account.":e==="IDEMPOTENCY_CONFLICT"||e==="ENGAGEMENT_STATE_CONFLICT"?"The item changed; reload and try again.":"The action could not be completed. Try again."}function K(e,t){if(!I||!E)return Promise.reject(new Error("AUTHENTICATION_REQUIRED"));let a=crypto.randomUUID();return new Promise((n,s)=>{let o=setTimeout(()=>{L.delete(a),s(new Error("REQUEST_TIMEOUT"))},1e4);L.set(a,{resolve:d=>{clearTimeout(o),n(d)},reject:d=>{clearTimeout(o),s(d)}}),I.contentWindow.postMessage({type:"gala-engagement-write",requestId:a,operation:e,payload:t},new URL(I.src).origin)})}document.addEventListener("submit",async e=>{let t=e.target.closest("[data-contact-form] form");if(!t)return;e.preventDefault();let a=t.closest("[data-contact-form]"),n=a.querySelector("[data-contact-status]");if(!E){n.textContent="Sign in with the account button before sending.";return}let s=new FormData(t);try{n.textContent="Sending\u2026",await K("contact.submit",{siteId:a.dataset.siteId,subject:s.get("subject"),message:s.get("message"),website:s.get("website")||null,phone:s.get("phone")||null}),t.reset(),n.textContent="Message sent."}catch(o){n.textContent=Q(o.message)}});async function W(e,t,a){let n=e.querySelector("[data-engagement-status]");try{return n&&(n.textContent="Saving\u2026"),await K(t,a),n&&(n.textContent="Saved."),await x(e,"",!1,!0),!0}catch(s){return n&&(n.textContent=Q(s.message)),!1}}if(I){let e=new URL(I.src).origin;window.addEventListener("message",t=>{if(t.origin!==e||t.source!==I.contentWindow)return;if(t.data?.type==="gala-engagement-result"){let o=L.get(t.data.requestId);if(!o)return;L.delete(t.data.requestId),t.data.ok===!0?o.resolve(t.data.result):o.reject(new Error(t.data.error?.code||"ENGAGEMENT_WRITE_FAILED"));return}if(t.data?.type==="gala-reader-state-result"){if(t.data.requestId!==_||t.data.ok!==!0)return;_=null;let o=new Set(Array.isArray(t.data.state?.reactions)?t.data.state.reactions:[]);document.querySelectorAll("[data-reaction]").forEach(d=>{d.setAttribute("aria-pressed",String(o.has(d.dataset.reaction)))}),document.querySelectorAll("[data-follow-article]").forEach(d=>{let f=t.data.state?.following===!0;Y(d,f)});return}if(t.data?.type==="gala-session-height"){let o=Number(t.data.height);Number.isFinite(o)&&o>0&&o<2e3&&(I.height=String(Math.ceil(o)));return}if(t.data?.type!=="gala-session")return;E=t.data.user&&typeof t.data.user.id=="string"?t.data.user:null;let a=document.querySelector("[data-user-control]"),n=E?.displayName;if(a){a.setAttribute("aria-label",n?`Account: ${n}`:"Sign in or view account"),a.title=n?`Account: ${n}`:"Account";let o=a.querySelector("[data-user-label]");o&&(o.textContent=n||"Sign in")}let s=B!==(E?.id??null);if(B=E?.id??null,E){let o=document.querySelector("[data-article-id]");o&&(_=crypto.randomUUID(),I.contentWindow.postMessage({type:"gala-reader-state-request",requestId:_,articleId:o.dataset.articleId},e))}document.querySelectorAll("[data-engagement-url]").forEach(o=>{s&&x(o)}),E&&S&&V()})}document.querySelectorAll("[data-gala-search]").forEach(e=>{let t=e.querySelector("form"),a=t?.elements.namedItem("q"),n=e.querySelector("[data-search-status]"),s=e.querySelector("[data-search-results]"),o=e.dataset.indexUrl,d,f=c=>String(c??"").normalize("NFKC").toLocaleLowerCase();function y(c,u){s.replaceChildren();for(let m of c){let p=document.createElement("li"),l=document.createElement("article"),h=document.createElement("h2"),w=document.createElement("a");if(w.href=m.url,w.lang=m.language,w.textContent=m.title,h.append(w),l.append(h),m.description){let k=document.createElement("p");k.textContent=m.description,l.append(k)}p.append(l),s.append(p)}n.textContent=`${c.length} result${c.length===1?"":"s"} for \u201C${u}\u201D.`}async function i(c){let u=c.trim();if(u===""){s.replaceChildren(),n.textContent="Enter a search term.";return}n.textContent="Searching\u2026";try{d??=fetch(o,{headers:{Accept:"application/json"}}).then(async l=>{if(!l.ok)throw new Error(`Search index returned HTTP ${l.status}`);let h=await l.json();if(h?.schemaVersion!==1||!Array.isArray(h.entries))throw new TypeError("Search index schema is unsupported");return h.entries});let m=f(u),p=(await d).filter(l=>f([l.title,l.description,l.language,...Array.isArray(l.tags)?l.tags:[],l.body].join(`
2
- `)).includes(m));y(p,u)}catch{s.replaceChildren(),n.textContent="Search is temporarily unavailable."}}t?.addEventListener("submit",c=>{c.preventDefault();let u=a.value,m=new URL(window.location.href);u.trim()===""?m.searchParams.delete("q"):m.searchParams.set("q",u),window.history.replaceState(null,"",m),i(u)});let r=new URLSearchParams(window.location.search).get("q")??"";a&&(a.value=r),i(r)});var T={value:null},A=document.querySelector("[data-gala-session-frame]"),z=A?new URL(A.src).origin:null,N=new Map;function X(e){return e==="AUTHENTICATION_REQUIRED"||e==="INVALID_BEARER_TOKEN"||e==="REAUTHENTICATION_REQUIRED"?"Sign in again to continue.":e==="ENGAGEMENT_RATE_LIMITED"?"You are posting too quickly; try again shortly.":e==="CONTACT_RATE_LIMITED"?"You are sending too quickly; try again later.":e==="RESOURCE_NOT_FOUND"?"That item is no longer available.":e==="INVALID_ENGAGEMENT_WRITE"||e==="INVALID_CONTACT_SUBMISSION"||e==="INVALID_REQUEST"?"Check your entry and try again.":e==="ACCESS_DENIED"?"That action is not available for this account.":e==="IDEMPOTENCY_CONFLICT"||e==="ENGAGEMENT_STATE_CONFLICT"?"The item changed; reload and try again.":"The action could not be completed. Try again."}function J(e,t){if(!A||!T.value)return Promise.reject(new Error("AUTHENTICATION_REQUIRED"));let a=crypto.randomUUID();return new Promise((n,s)=>{let o=setTimeout(()=>{N.delete(a),s(new Error("REQUEST_TIMEOUT"))},1e4);N.set(a,{resolve:d=>{clearTimeout(o),n(d)},reject:d=>{clearTimeout(o),s(d)}}),A.contentWindow.postMessage({type:"gala-engagement-write",requestId:a,operation:e,payload:t},z)})}function U(e){document.dispatchEvent(new CustomEvent("gala-request-sign-in",{detail:e}))}A&&window.addEventListener("message",e=>{if(e.origin!==z||e.source!==A.contentWindow)return;if(e.data?.type==="gala-engagement-result"){let a=N.get(e.data.requestId);if(!a)return;N.delete(e.data.requestId),e.data.ok===!0?a.resolve(e.data.result):a.reject(new Error(e.data.error?.code||"ENGAGEMENT_WRITE_FAILED"));return}if(e.data?.type!=="gala-session")return;let t=e.data.user;T.value=t&&typeof t.id=="string"?t:null,window.dispatchEvent(new CustomEvent("gala-session-change"))});var ie=5,g=(e,t,a)=>{let n=document.createElement(e);return t&&(n.className=t),a!==void 0&&(n.textContent=a),n};function ce(e){let t=new Map;for(let n of e){let s=n.parentCommentId??"";t.has(s)||t.set(s,[]),t.get(s).push(n)}let a=(n,s)=>(t.get(n)??[]).map(o=>({...o,depth:s,replies:a(o.commentId,s+1)}));return a("",0)}function le(e,t){let a={items:[],cursor:null,total:0,busy:!1,status:"",phase:"loading"},n=/\/v1\/articles\/([^/]+)\/engagement/.exec(t)?.[1]??"",s=e.closest(".gala-conversation")?.querySelector("[data-engagement-status]");async function o(r="",{append:c=!1,fresh:u=!1}={}){let m=new URL(t);r&&m.searchParams.set("commentsCursor",r);let p=await fetch(m,{headers:{Accept:"application/json"},credentials:"omit",cache:u?"no-store":"default"});if(!p.ok)throw new Error(`Comments returned HTTP ${p.status}`);let l=(await p.json())?.data?.comments;if(!l||!Array.isArray(l.items))throw new TypeError("Comment page is invalid");a.items=c?[...a.items,...l.items]:l.items,a.cursor=l.nextCursor??null,Number.isSafeInteger(l.totalCount)&&(a.total=l.totalCount)}async function d(r,c){if(!T.value)return U({kind:"comment"}),!1;a.busy=!0,a.status="",i();try{return await J(r,c),await o("",{fresh:!0}),!0}catch(u){return a.status=X(u.message),!1}finally{a.busy=!1,i()}}function f(r,c,u){let m=g("form","gala-comment__form"),p=g("textarea");p.rows=3,p.value=c,p.placeholder=r,p.setAttribute("aria-label",r);let l=g("button","","Post");return l.type="submit",l.disabled=a.busy,m.append(p,l),m.addEventListener("submit",async h=>{h.preventDefault();let w=p.value.trim();w&&await u(w)&&(p.value="")}),m}function y(r){let c=g("li","gala-comment");c.dataset.commentId=r.commentId,c.dataset.depth=r.depth;let u=g("p","gala-comment__meta");if(u.append(g("strong","",r.author?.displayName??"[deleted]")),r.createdAt){let m=g("time","",new Date(r.createdAt).toLocaleDateString());m.dateTime=r.createdAt,u.append(m)}if(c.append(u,g("p","gala-comment__body",r.deleted?"[deleted]":r.body)),!r.deleted){let m=g("div","gala-comment-actions");if(r.depth<ie){let l=g("button","","Reply");l.type="button",l.dataset.replyComment=r.commentId,l.addEventListener("click",()=>{let h=c.querySelector(":scope > .gala-comment__form");if(h){h.remove();return}m.after(f(`Reply to ${r.author?.displayName??"this comment"}`,"",w=>d("comment.create",{articleId:n,parentCommentId:r.commentId,body:w})))}),m.append(l)}if(T.value&&r.author?.userId===T.value.id){let l=g("button","","Edit");l.type="button",l.dataset.editComment=r.commentId,l.addEventListener("click",()=>m.after(f("Edit your comment",r.body??"",w=>d("comment.edit",{articleId:n,commentId:r.commentId,body:w}))));let h=g("button","","Delete");h.type="button",h.dataset.deleteComment=r.commentId,h.addEventListener("click",()=>d("comment.delete",{articleId:n,commentId:r.commentId})),m.append(l,h)}else{let l=g("button","","Report");l.type="button",l.dataset.reportComment=r.commentId,l.addEventListener("click",()=>d("comment.report",{articleId:n,commentId:r.commentId,reason:"OTHER"})),m.append(l)}c.append(m)}if(r.replies.length){let m=g("ol","gala-comment-replies");m.append(...r.replies.map(y)),c.append(m)}return c}function i(){if(s&&(s.textContent=a.phase==="loading"?"Loading comments\u2026":a.phase==="unavailable"?"Comments are temporarily unavailable.":a.status),a.phase!=="ready"){e.replaceChildren();return}let r=g("section","gala-comments-island");if(r.setAttribute("aria-label","Comments"),r.append(g("p","gala-comments__heading",a.total===1?"1 comment":`${a.total} comments`)),T.value)r.append(f("Add a comment","",c=>d("comment.create",{articleId:n,body:c})));else{let c=g("p","gala-comments__prompt"),u=g("button","","Sign in to join the conversation");u.type="button",u.addEventListener("click",()=>U({kind:"comment"})),c.append(u),r.append(c)}if(!a.items.length)r.append(g("p","gala-comments__empty","No comments yet."));else{let c=g("ol","gala-comments");c.append(...ce(a.items).map(y)),r.append(c)}if(a.cursor){let c=g("button","gala-comments__more","Show more comments");c.type="button",c.disabled=a.busy,c.addEventListener("click",async()=>{a.busy=!0,a.status="Loading more comments\u2026",i();try{await o(a.cursor,{append:!0}),a.status=""}catch{a.status="More comments couldn\u2019t be loaded. Try again."}a.busy=!1,i()}),r.append(c)}e.replaceChildren(r)}window.addEventListener("gala-session-change",i),i(),o().then(()=>{a.phase="ready"}).catch(()=>{a.phase="unavailable"}).finally(i)}document.querySelectorAll("[data-gala-comments]").forEach(e=>{let t=e.closest("[data-engagement-url]")?.dataset.engagementUrl;t&&le(e,t)});})();
1
+ (()=>{var I=["system","light","dark"],G="gala-color-mode";function P(){let e=document.documentElement.dataset.mode;return I.includes(e)?e:"system"}function oe(){try{let e=localStorage.getItem(G);if(I.includes(e))return e}catch{return P()}return P()}function H(e){document.documentElement.dataset.mode=e;let n=I[(I.indexOf(e)+1)%I.length];document.querySelectorAll("[data-theme-mode-toggle]").forEach(t=>{let a=t.querySelector?.("[data-theme-mode-label]");a?a.textContent=`Theme: ${e}`:t.textContent=`Theme: ${e}`,t.setAttribute("aria-label",`Color mode: ${e}. Activate for ${n}.`)})}document.addEventListener("DOMContentLoaded",()=>{H(oe()),document.querySelectorAll("[data-theme-mode-toggle]").forEach(e=>{e.addEventListener("click",()=>{let n=I[(I.indexOf(document.documentElement.dataset.mode)+1)%I.length];try{localStorage.setItem(G,n)}catch{}H(n)})})});var j="gala-language-preference";function se(){try{return localStorage.getItem(j)}catch{return null}}function $(e,n){return[...e.options].find(t=>t.value===n)}document.addEventListener("DOMContentLoaded",()=>{let e=se();document.querySelectorAll("[data-language-preference]").forEach(n=>{e!=null&&$(n,e)!=null&&(n.value=e),n.addEventListener("change",()=>{try{localStorage.setItem(j,n.value)}catch{}if(!n.hasAttribute("data-navigate-on-selection"))return;let t=$(n,n.value);t?.dataset.url&&window.location.assign(t.dataset.url)})})});var B="gala.prism.session.v1";document.addEventListener("click",e=>{if(e.target.closest("[data-prism-restore]")){try{sessionStorage.removeItem(B)}catch{}return}let t=e.target.closest("[data-prism-select]");if(t)try{sessionStorage.setItem(B,JSON.stringify({articleId:t.dataset.prismArticleId,language:t.dataset.prismLanguage,configurationId:t.dataset.prismConfigurationId,sourceRevisionHash:t.dataset.prismSourceHash,selectedAt:new Date().toISOString()}))}catch{}});function L(e){let n=e.closest(".gala-share"),t=n?.querySelector(".gala-share__fallback");t?.classList.add("gala-share__fallback--visible"),t?.focus(),t?.select();let a=n?.querySelector(".gala-share__status");a&&(a.textContent="Select and copy the URL shown.")}var W=document.querySelector("[data-reading-progress]"),U=document.querySelector(".gala-markdown");if(W&&U){let e=null,n=()=>{e=null;let a=U.offsetTop,r=Math.max(1,U.offsetHeight-window.innerHeight),l=Math.min(1,Math.max(0,(window.scrollY-a)/r));W.value=l},t=()=>{e==null&&(e=requestAnimationFrame(n))};addEventListener("scroll",t,{passive:!0}),addEventListener("resize",t,{passive:!0}),t()}var T=document.querySelector(".gala-toc");if(T?.tagName==="DETAILS"){let e=T.querySelector("nav"),n=[...T.querySelectorAll('a[href^="#"]')],t=n.map(m=>document.getElementById(m.hash.slice(1))).filter(Boolean),a=null,r=()=>{if(a=null,T.classList.toggle("gala-toc--floating",T.getBoundingClientRect().top<=96),!t.length)return;let m=window.innerHeight*.42,f=t[0];for(let s of t)if(s.getBoundingClientRect().top<=m)f=s;else break;let E=n.find(s=>s.hash===`#${f.id}`);for(let s of n)s===E?s.setAttribute("aria-current","location"):s.removeAttribute("aria-current");if(e&&n.length){let s=n[0].getBoundingClientRect(),o=n[n.length-1].getBoundingClientRect();T.classList.toggle("gala-toc--overflowing",o.bottom-s.top>e.clientHeight)}if(E&&e&&e.scrollHeight>e.clientHeight){let s=e.getBoundingClientRect(),o=E.getBoundingClientRect(),i=e.scrollTop+o.top-s.top-(e.clientHeight-o.height)/2;e.scrollTo({top:Math.max(0,i),behavior:"auto"})}},l=()=>{a==null&&(a=requestAnimationFrame(r))};addEventListener("scroll",l,{passive:!0}),addEventListener("resize",l,{passive:!0}),l()}var Y=document.querySelector(".gala-action-rail"),V=document.querySelector("[data-action-dock]");if(Y&&V){let e=n=>{Y.classList.toggle("gala-action-rail--integrated",n[0].isIntersecting)};new IntersectionObserver(e,{rootMargin:"0px 0px 18% 0px",threshold:0}).observe(V)}function X(e,n){let t=n?"Unfollow article":"Follow article";e.setAttribute("aria-pressed",String(n)),e.setAttribute("aria-label",t),e.title=t;let a=e.querySelector("[data-follow-label]");a&&(a.textContent=t)}document.addEventListener("click",async e=>{if(e.target instanceof HTMLDialogElement&&e.target.open){let s=e.target.getBoundingClientRect();if(e.clientX<s.left||e.clientX>s.right||e.clientY<s.top||e.clientY>s.bottom){e.target.close();return}}let n=e.target.closest("[data-gala-embed-load]");if(n){let s=n.closest("[data-gala-embed]"),o=n.dataset.galaEmbedSrc,i=n.dataset.galaEmbedLoad;if(!s||!o||!["youtube","codepen"].includes(i))return;let d=document.createElement("iframe");d.src=o,d.title=i==="youtube"?"YouTube video":"CodePen example",d.loading="eager",d.referrerPolicy="strict-origin-when-cross-origin",d.setAttribute("sandbox","allow-forms allow-popups allow-presentation allow-same-origin allow-scripts"),d.setAttribute("allow",i==="youtube"?"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share":"fullscreen"),d.setAttribute("allowfullscreen",""),s.replaceChildren(d);return}let t=e.target.closest("[data-open-dialog]");if(t){let s=document.getElementById(t.dataset.openDialog);s instanceof HTMLDialogElement&&s.showModal();return}let a=e.target.closest("[data-reaction]");if(a){let s=a.closest("[data-engagement-url]");if(!s)return;if(!w)return k({kind:"reaction",region:s,selector:`[data-reaction="${a.dataset.reaction}"]`});let o=a.getAttribute("aria-pressed")!=="true";if(!await z(s,o?"reaction.add":"reaction.remove",{articleId:s.dataset.articleId,reaction:a.dataset.reaction}))return;a.setAttribute("aria-pressed",String(o));return}let r=e.target.closest("[data-follow-article]");if(r){let s=r.closest("[data-engagement-url]");if(!s)return;if(!w)return k({kind:"follow",region:s,selector:"[data-follow-article]"});let o=r.getAttribute("aria-pressed")!=="true";if(!await z(s,o?"follow.add":"follow.remove",{targetType:"articles",targetId:s.dataset.articleId}))return;X(r,o);return}let l=e.target.closest("[data-copy-url]");if(l){let s=l.dataset.copyUrl;if(!window.isSecureContext||!navigator.clipboard?.writeText){L(l);return}try{await navigator.clipboard.writeText(s);let o=l.closest(".gala-share")?.querySelector(".gala-share__status");o&&(o.textContent="Link copied.")}catch{L(l)}return}let m=e.target.closest("[data-native-share]");if(m){if(navigator.share)try{await navigator.share({title:document.title,url:m.dataset.nativeShare})}catch(s){s.name!=="AbortError"&&L(m)}else L(m);return}let f=e.target.closest("[data-copy-code]");if(!f)return;let E=f.closest(".gala-code-block")?.querySelector("code");if(!(!E||!navigator.clipboard?.writeText||!window.isSecureContext))try{await navigator.clipboard.writeText(E.textContent),f.textContent="Copied"}catch{f.textContent="Select code to copy"}});var ie=new Set([...document.querySelectorAll("pre code")].map(e=>e.closest("pre")).filter(Boolean));ie.forEach(e=>{let n=document.createElement("div");n.className="gala-code-block",e.before(n),n.append(e);let t=document.createElement("button");t.type="button",t.dataset.copyCode="",t.textContent="Copy code",t.setAttribute("aria-label","Copy code block"),n.prepend(t)});function ce(e){return[["Reactions",Object.values(e.reactions??{}).reduce((t,a)=>t+(Number.isSafeInteger(a)?a:0),0)],["Comments",Number.isSafeInteger(e.comments?.totalCount)?e.comments.totalCount:0],["Views",Number.isSafeInteger(e.views?.count)?e.views.count:0]]}function le(e){return e<1e3?"<1K":new Intl.NumberFormat("en",{notation:"compact",maximumFractionDigits:1}).format(e)}function de(e,n){let t=n?.data;if(!t||typeof t!="object")throw new TypeError("Engagement data is invalid");for(let[a,r]of ce(t))e.querySelectorAll(`[data-engagement-stat="${a.toLowerCase()}"]`).forEach(l=>{l.textContent=le(r),l.closest("div")?.setAttribute("title",`${r} ${a.toLowerCase()}`)});e.querySelector("[data-engagement-snapshot]")?.remove(),e.querySelector(".gala-engagement__placeholder")?.remove()}async function D(e,n="",t=!1,a=!1){let r=e.querySelector("[data-engagement-status]"),l=!!e.querySelector("[data-gala-comments]");try{let m=new URL(e.dataset.engagementUrl);n&&m.searchParams.set("commentsCursor",n);let f=await fetch(m,{headers:{Accept:"application/json"},credentials:"omit",cache:a?"no-store":"default"});if(!f.ok)throw new Error(`Engagement returned HTTP ${f.status}`);let E=await f.json();de(e,E),r&&!l&&(r.textContent=E.errors?.length?"Some engagement data is temporarily unavailable.":"")}catch{r&&!l&&(r.textContent="Engagement is temporarily unavailable.")}}function ue(){let e=new URL(window.location.href).searchParams,n={};for(let t of["utm_source","utm_medium","utm_campaign","utm_content","utm_term"]){let a=e.get(t);a&&[...a].length<=128&&(n[t]=a)}return n}function me(e){let n=new URL(e.dataset.engagementUrl);n.pathname=n.pathname.replace(/\/engagement$/,"/views"),fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({language:document.documentElement.lang||void 0,referrer:document.referrer||void 0,campaign:ue()}),credentials:"omit",keepalive:!0}).catch(()=>{})}document.addEventListener("gala-request-sign-in",e=>{w||C||k({kind:e.detail?.kind??"comment"})});var w=null,Q=null,N=null,q=new Map,C=null,y=document.querySelector("[data-gala-session-frame]"),_=y?new URL(y.src).origin:null,J=!1,v=null,R=null;function Z(){!J||!y||!v||(y.contentWindow?.postMessage({type:"gala-session-transfer",transferCode:v},_),v=null)}function K(){y?.contentWindow?.postMessage({type:"gala-session-request"},_)}y&&(y.addEventListener("load",K),K());async function M(e){let n=document.querySelector("[data-engagement-status]");if(!R)return!1;if(!globalThis.IdentityCredential||typeof navigator.credentials?.get!="function")return n&&(n.textContent="FedCM is not available in this browser. Use a current browser to sign in."),!1;try{let a={configURL:"https://api.gala67.com/v1/fedcm/config.json",clientId:new URL(y.src).searchParams.get("siteId")??"",params:{nonce:R}};e==="active"&&(a.mode="active");let r=await navigator.credentials.get({identity:{providers:[a]},mediation:e==="active"?"required":"silent"});return typeof r?.token!="string"?!1:(v=r.token,Z(),!0)}catch(t){return t?.name!=="NotAllowedError"&&console.error("Gala FedCM sign-in failed.",t),e==="active"&&n&&(n.textContent="Sign-in did not finish. Try again."),!1}}function k(e){let n=e.field;C={kind:e.kind,region:e.region,selector:e.selector,draft:n?n.value:null,caret:n?n.selectionStart:null},n&&n.blur(),M("active").then(t=>{t||(C=null)})}function ge(){let e=C;if(!e||!document.hasFocus())return;let n=e.region?.querySelector(e.selector);if(n){if(C=null,e.kind==="comment"){e.draft!=null&&n.value===""&&(n.value=e.draft),n.focus(),e.caret!=null&&typeof n.setSelectionRange=="function"&&n.setSelectionRange(e.caret,e.caret);return}n.click()}}document.querySelectorAll("[data-engagement-url]").forEach(e=>{D(e),me(e)});function ee(e){return e==="AUTHENTICATION_REQUIRED"||e==="INVALID_BEARER_TOKEN"||e==="REAUTHENTICATION_REQUIRED"?"Sign in again to continue.":e==="ENGAGEMENT_RATE_LIMITED"?"You are posting too quickly; try again shortly.":e==="CONTACT_RATE_LIMITED"?"You are sending too quickly; try again later.":e==="RESOURCE_NOT_FOUND"?"That item is no longer available.":e==="INVALID_ENGAGEMENT_WRITE"||e==="INVALID_CONTACT_SUBMISSION"||e==="INVALID_REQUEST"?"Check your entry and try again.":e==="ACCESS_DENIED"?"That action is not available for this account.":e==="IDEMPOTENCY_CONFLICT"||e==="ENGAGEMENT_STATE_CONFLICT"?"The item changed; reload and try again.":"The action could not be completed. Try again."}function te(e,n){if(!y||!w)return Promise.reject(new Error("AUTHENTICATION_REQUIRED"));let t=crypto.randomUUID();return new Promise((a,r)=>{let l=setTimeout(()=>{q.delete(t),r(new Error("REQUEST_TIMEOUT"))},1e4);q.set(t,{resolve:m=>{clearTimeout(l),a(m)},reject:m=>{clearTimeout(l),r(m)}}),y.contentWindow.postMessage({type:"gala-engagement-write",requestId:t,operation:e,payload:n},new URL(y.src).origin)})}document.addEventListener("submit",async e=>{let n=e.target.closest("[data-contact-form] form");if(!n)return;e.preventDefault();let t=n.closest("[data-contact-form]"),a=t.querySelector("[data-contact-status]");if(!w){a.textContent="Sign in with the account button before sending.";return}let r=new FormData(n);try{a.textContent="Sending\u2026",await te("contact.submit",{siteId:t.dataset.siteId,subject:r.get("subject"),message:r.get("message"),website:r.get("website")||null,phone:r.get("phone")||null}),n.reset(),a.textContent="Message sent."}catch(l){a.textContent=ee(l.message)}});async function z(e,n,t){let a=e.querySelector("[data-engagement-status]");try{return a&&(a.textContent="Saving\u2026"),await te(n,t),a&&(a.textContent="Saved."),await D(e,"",!1,!0),!0}catch(r){return a&&(a.textContent=ee(r.message)),!1}}y&&window.addEventListener("message",e=>{if(e.origin!==_||e.source!==y.contentWindow)return;if(e.data?.type==="gala-engagement-result"){let r=q.get(e.data.requestId);if(!r)return;q.delete(e.data.requestId),e.data.ok===!0?r.resolve(e.data.result):r.reject(new Error(e.data.error?.code||"ENGAGEMENT_WRITE_FAILED"));return}if(e.data?.type==="gala-reader-state-result"){if(e.data.requestId!==N||e.data.ok!==!0)return;N=null;let r=new Set(Array.isArray(e.data.state?.reactions)?e.data.state.reactions:[]);document.querySelectorAll("[data-reaction]").forEach(l=>{l.setAttribute("aria-pressed",String(r.has(l.dataset.reaction)))}),document.querySelectorAll("[data-follow-article]").forEach(l=>{let m=e.data.state?.following===!0;X(l,m)});return}if(e.data?.type==="gala-session-height"){let r=Number(e.data.height);Number.isFinite(r)&&r>0&&r<2e3&&(y.height=String(Math.ceil(r)));return}if(e.data?.type!=="gala-session")return;J=!0,typeof e.data.frameToken=="string"&&(R=e.data.frameToken),v&&Z(),w=e.data.user&&typeof e.data.user.id=="string"?e.data.user:null;let n=document.querySelector("[data-user-control]"),t=w?.displayName;if(n){n.setAttribute("aria-label",t?`Account: ${t}`:"Sign in or view account"),n.title=t?`Account: ${t}`:"Account";let r=n.querySelector("[data-user-label]");r&&(r.textContent=t||"Sign in")}let a=Q!==(w?.id??null);if(Q=w?.id??null,w){let r=document.querySelector("[data-article-id]");r&&(N=crypto.randomUUID(),y.contentWindow.postMessage({type:"gala-reader-state-request",requestId:N,articleId:r.dataset.articleId},_))}document.querySelectorAll("[data-engagement-url]").forEach(r=>{a&&D(r)}),w&&C&&ge(),!w&&R&&M("passive")});window.addEventListener("message",e=>{e.origin!==_||e.source!==y?.contentWindow||e.data?.type==="gala-fedcm-sign-in"&&M("active")});document.querySelectorAll("[data-gala-search]").forEach(e=>{let n=e.querySelector("form"),t=n?.elements.namedItem("q"),a=e.querySelector("[data-search-status]"),r=e.querySelector("[data-search-results]"),l=e.dataset.indexUrl,m,f=i=>String(i??"").normalize("NFKC").toLocaleLowerCase();function E(i,d){r.replaceChildren();for(let u of i){let p=document.createElement("li"),c=document.createElement("article"),h=document.createElement("h2"),b=document.createElement("a");if(b.href=u.url,b.lang=u.language,b.textContent=u.title,h.append(b),c.append(h),u.description){let F=document.createElement("p");F.textContent=u.description,c.append(F)}p.append(c),r.append(p)}a.textContent=`${i.length} result${i.length===1?"":"s"} for \u201C${d}\u201D.`}async function s(i){let d=i.trim();if(d===""){r.replaceChildren(),a.textContent="Enter a search term.";return}a.textContent="Searching\u2026";try{m??=fetch(l,{headers:{Accept:"application/json"}}).then(async c=>{if(!c.ok)throw new Error(`Search index returned HTTP ${c.status}`);let h=await c.json();if(h?.schemaVersion!==1||!Array.isArray(h.entries))throw new TypeError("Search index schema is unsupported");return h.entries});let u=f(d),p=(await m).filter(c=>f([c.title,c.description,c.language,...Array.isArray(c.tags)?c.tags:[],c.body].join(`
2
+ `)).includes(u));E(p,d)}catch{r.replaceChildren(),a.textContent="Search is temporarily unavailable."}}n?.addEventListener("submit",i=>{i.preventDefault();let d=t.value,u=new URL(window.location.href);d.trim()===""?u.searchParams.delete("q"):u.searchParams.set("q",d),window.history.replaceState(null,"",u),s(d)});let o=new URLSearchParams(window.location.search).get("q")??"";t&&(t.value=o),s(o)});var S={value:null},A=document.querySelector("[data-gala-session-frame]"),ne=A?new URL(A.src).origin:null,x=new Map;function ae(e){return e==="AUTHENTICATION_REQUIRED"||e==="INVALID_BEARER_TOKEN"||e==="REAUTHENTICATION_REQUIRED"?"Sign in again to continue.":e==="ENGAGEMENT_RATE_LIMITED"?"You are posting too quickly; try again shortly.":e==="CONTACT_RATE_LIMITED"?"You are sending too quickly; try again later.":e==="RESOURCE_NOT_FOUND"?"That item is no longer available.":e==="INVALID_ENGAGEMENT_WRITE"||e==="INVALID_CONTACT_SUBMISSION"||e==="INVALID_REQUEST"?"Check your entry and try again.":e==="ACCESS_DENIED"?"That action is not available for this account.":e==="IDEMPOTENCY_CONFLICT"||e==="ENGAGEMENT_STATE_CONFLICT"?"The item changed; reload and try again.":"The action could not be completed. Try again."}function re(e,n){if(!A||!S.value)return Promise.reject(new Error("AUTHENTICATION_REQUIRED"));let t=crypto.randomUUID();return new Promise((a,r)=>{let l=setTimeout(()=>{x.delete(t),r(new Error("REQUEST_TIMEOUT"))},1e4);x.set(t,{resolve:m=>{clearTimeout(l),a(m)},reject:m=>{clearTimeout(l),r(m)}}),A.contentWindow.postMessage({type:"gala-engagement-write",requestId:t,operation:e,payload:n},ne)})}function O(e){document.dispatchEvent(new CustomEvent("gala-request-sign-in",{detail:e}))}A&&window.addEventListener("message",e=>{if(e.origin!==ne||e.source!==A.contentWindow)return;if(e.data?.type==="gala-engagement-result"){let t=x.get(e.data.requestId);if(!t)return;x.delete(e.data.requestId),e.data.ok===!0?t.resolve(e.data.result):t.reject(new Error(e.data.error?.code||"ENGAGEMENT_WRITE_FAILED"));return}if(e.data?.type!=="gala-session")return;let n=e.data.user;S.value=n&&typeof n.id=="string"?n:null,window.dispatchEvent(new CustomEvent("gala-session-change"))});var fe=5,g=(e,n,t)=>{let a=document.createElement(e);return n&&(a.className=n),t!==void 0&&(a.textContent=t),a};function pe(e){let n=new Map;for(let a of e){let r=a.parentCommentId??"";n.has(r)||n.set(r,[]),n.get(r).push(a)}let t=(a,r)=>(n.get(a)??[]).map(l=>({...l,depth:r,replies:t(l.commentId,r+1)}));return t("",0)}function he(e,n){let t={items:[],cursor:null,total:0,busy:!1,status:"",phase:"loading"},a=/\/v1\/articles\/([^/]+)\/engagement/.exec(n)?.[1]??"",r=e.closest(".gala-conversation")?.querySelector("[data-engagement-status]");async function l(o="",{append:i=!1,fresh:d=!1}={}){let u=new URL(n);o&&u.searchParams.set("commentsCursor",o);let p=await fetch(u,{headers:{Accept:"application/json"},credentials:"omit",cache:d?"no-store":"default"});if(!p.ok)throw new Error(`Comments returned HTTP ${p.status}`);let c=(await p.json())?.data?.comments;if(!c||!Array.isArray(c.items))throw new TypeError("Comment page is invalid");t.items=i?[...t.items,...c.items]:c.items,t.cursor=c.nextCursor??null,Number.isSafeInteger(c.totalCount)&&(t.total=c.totalCount)}async function m(o,i){if(!S.value)return O({kind:"comment"}),!1;t.busy=!0,t.status="",s();try{return await re(o,i),await l("",{fresh:!0}),!0}catch(d){return t.status=ae(d.message),!1}finally{t.busy=!1,s()}}function f(o,i,d){let u=g("form","gala-comment__form"),p=g("textarea");p.rows=3,p.value=i,p.placeholder=o,p.setAttribute("aria-label",o);let c=g("button","","Post");return c.type="submit",c.disabled=t.busy,u.append(p,c),u.addEventListener("submit",async h=>{h.preventDefault();let b=p.value.trim();b&&await d(b)&&(p.value="")}),u}function E(o){let i=g("li","gala-comment");i.dataset.commentId=o.commentId,i.dataset.depth=o.depth;let d=g("p","gala-comment__meta");if(d.append(g("strong","",o.author?.displayName??"[deleted]")),o.createdAt){let u=g("time","",new Date(o.createdAt).toLocaleDateString());u.dateTime=o.createdAt,d.append(u)}if(i.append(d,g("p","gala-comment__body",o.deleted?"[deleted]":o.body)),!o.deleted){let u=g("div","gala-comment-actions");if(o.depth<fe){let c=g("button","","Reply");c.type="button",c.dataset.replyComment=o.commentId,c.addEventListener("click",()=>{let h=i.querySelector(":scope > .gala-comment__form");if(h){h.remove();return}u.after(f(`Reply to ${o.author?.displayName??"this comment"}`,"",b=>m("comment.create",{articleId:a,parentCommentId:o.commentId,body:b})))}),u.append(c)}if(S.value&&o.author?.userId===S.value.id){let c=g("button","","Edit");c.type="button",c.dataset.editComment=o.commentId,c.addEventListener("click",()=>u.after(f("Edit your comment",o.body??"",b=>m("comment.edit",{articleId:a,commentId:o.commentId,body:b}))));let h=g("button","","Delete");h.type="button",h.dataset.deleteComment=o.commentId,h.addEventListener("click",()=>m("comment.delete",{articleId:a,commentId:o.commentId})),u.append(c,h)}else{let c=g("button","","Report");c.type="button",c.dataset.reportComment=o.commentId,c.addEventListener("click",()=>m("comment.report",{articleId:a,commentId:o.commentId,reason:"OTHER"})),u.append(c)}i.append(u)}if(o.replies.length){let u=g("ol","gala-comment-replies");u.append(...o.replies.map(E)),i.append(u)}return i}function s(){if(r&&(r.textContent=t.phase==="loading"?"Loading comments\u2026":t.phase==="unavailable"?"Comments are temporarily unavailable.":t.status),t.phase!=="ready"){e.replaceChildren();return}let o=g("section","gala-comments-island");if(o.setAttribute("aria-label","Comments"),o.append(g("p","gala-comments__heading",t.total===1?"1 comment":`${t.total} comments`)),S.value)o.append(f("Add a comment","",i=>m("comment.create",{articleId:a,body:i})));else{let i=g("p","gala-comments__prompt"),d=g("button","","Sign in to join the conversation");d.type="button",d.addEventListener("click",()=>O({kind:"comment"})),i.append(d),o.append(i)}if(!t.items.length)o.append(g("p","gala-comments__empty","No comments yet."));else{let i=g("ol","gala-comments");i.append(...pe(t.items).map(E)),o.append(i)}if(t.cursor){let i=g("button","gala-comments__more","Show more comments");i.type="button",i.disabled=t.busy,i.addEventListener("click",async()=>{t.busy=!0,t.status="Loading more comments\u2026",s();try{await l(t.cursor,{append:!0}),t.status=""}catch{t.status="More comments couldn\u2019t be loaded. Try again."}t.busy=!1,s()}),o.append(i)}e.replaceChildren(o)}window.addEventListener("gala-session-change",s),s(),l().then(()=>{t.phase="ready"}).catch(()=>{t.phase="unavailable"}).finally(s)}document.querySelectorAll("[data-gala-comments]").forEach(e=>{let n=e.closest("[data-engagement-url]")?.dataset.engagementUrl;n&&he(e,n)});})();