Socket
Socket
Sign inDemoInstall

swup

Package Overview
Dependencies
Maintainers
1
Versions
142
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

swup - npm Package Compare versions

Comparing version 3.1.1 to 4.0.0-rc.14

dist/types/modules/__test__/fetchPage.test.d.ts

2

dist/Swup.modern.js

@@ -1,2 +0,2 @@

import t from"delegate-it";function e(){return e=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t},e.apply(this,arguments)}const n=(t,e)=>String(t).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||e||"",i=({hash:t}={})=>location.pathname+location.search+(t?location.hash:""),s=(t,n={})=>{const s=e({url:t=t||i({hash:!0}),random:Math.random(),source:"swup"},n);history.pushState(s,"",t)},o=(t=null,n={})=>{t=t||i({hash:!0});const s=e({},history.state,{url:t,random:Math.random(),source:"swup"},n);history.replaceState(s,"",t)},r=(e,n,i,s)=>{const o=new AbortController;return t(e,n,i,s),{destroy:()=>o.abort()}},a=(t,e=document)=>e.querySelector(t),l=(t,e=document)=>Array.from(e.querySelectorAll(t)),c=t=>{requestAnimationFrame(()=>{requestAnimationFrame(()=>{t()})})},u=t=>window.CSS&&window.CSS.escape?CSS.escape(t):t,h=t=>1e3*Number(t.slice(0,-1).replace(",",".")),d=(t,e)=>{var n,i;let s=document.createElement("html");s.innerHTML=t;let o=[];e.forEach(t=>{if(null==a(t,s))return console.warn(`[swup] Container ${t} not found on page.`),null;l(t).length!==l(t,s).length&&console.warn("[swup] Mismatched number of containers found on new page."),l(t).forEach((e,n)=>{l(t,s)[n].setAttribute("data-swup",String(o.length)),o.push(l(t,s)[n].outerHTML)})});const r=(null==(n=a("title",s))?void 0:n.innerText)||"",c=null==(i=a("body",s))?void 0:i.className;return s.innerHTML="",s=null,{title:r,pageClass:c,blocks:o,originalContent:t}},p=(t,n)=>{const i={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:s,method:o,headers:r,data:a}=e({},i,t),l=new XMLHttpRequest;return l.onreadystatechange=function(){4===l.readyState&&n(l)},l.open(o,s,!0),Object.entries(r).forEach(([t,e])=>{l.setRequestHeader(t,e)}),l.send(a),l};class g extends URL{constructor(t,e=document.baseURI){super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new g(e)}static fromUrl(t){return new g(t)}}const m=(t,e)=>{let n=0;e.forEach(e=>{null==a(e,t)?console.warn(`[swup] Container ${e} not found on page.`):l(e).forEach((i,s)=>{l(e,t)[s].setAttribute("data-swup",String(n)),n++})})},f=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),v=()=>{const t=document.documentElement.className.split(" ").filter(f);document.documentElement.classList.remove(...t)};class w{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(g.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(i())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const E=function({event:t,skipTransition:e}={}){if(e)return this.triggerEvent("transitionEnd",t),this.cleanupAnimationClasses(),[Promise.resolve()];c(()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")});const n=this.getAnimationPromises("in");return Promise.all(n).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",t),this.cleanupAnimationClasses()}),n},P=t=>{if(t&&"#"===t.charAt(0)&&(t=t.substring(1)),!t)return null;const e=decodeURIComponent(t);let n=document.getElementById(t)||document.getElementById(e)||a(`a[name='${u(t)}']`)||a(`a[name='${u(e)}']`);return n||"top"!==t||(n=document.body),n};let S="transition",b="transitionend",y="animation",U="animationend";function k(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=l(e,document.body);if(!n.length)return console.warn(`[swup] No elements found matching animationSelector \`${e}\``),[Promise.resolve()];const i=n.map(t=>function(t){const{type:e,timeout:n,propCount:i}=function(t,e=null){const n=window.getComputedStyle(t),i=`${S}Duration`,s=`${y}Delay`,o=`${y}Duration`,r=n[`${S}Delay`].split(", "),a=(n[i]||"").split(", "),l=L(r,a),c=(n[s]||"").split(", "),u=(n[o]||"").split(", "),h=L(c,u);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=u.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:u.length:0),{type:d,timeout:p,propCount:g}}(t);if(e&&n)return new Promise(s=>{const o="transition"===e?b:U,r=performance.now();let a=0;const l=()=>{t.removeEventListener(o,c),s()},c=e=>{if(e.target===t){if(!(t=>[b,U].includes(t.type))(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=i&&l()}};setTimeout(()=>{a<i&&l()},n+1),t.addEventListener(o,c)})}(t)).filter(Boolean);return i.length?i:(console.warn(`[swup] No CSS animation duration defined on elements matching \`${e}\``),[Promise.resolve()])}function L(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>h(e)+h(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(S="WebkitTransition",b="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(y="WebkitAnimation",U="webkitAnimationEnd");const C=function(t){const n=d(t.responseText,this.options.containers);return n?e({},n,{responseURL:t.responseURL||window.location.href}):(console.warn("[swup] Received page is invalid."),null)};function T(t){const n=this.options.requestHeaders,{url:i}=t;return this.cache.exists(i)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(i))):new Promise((s,o)=>{p(e({},t,{headers:n}),t=>{if(500===t.status)return this.triggerEvent("serverError"),void o(i);const n=this.getPageData(t);if(!n||!n.blocks.length)return void o(i);const r=e({},n,{url:i});this.cache.cacheUrl(r),this.triggerEvent("pageLoaded"),s(r)})})}const H=function({event:t,skipTransition:e}={}){const n=t instanceof PopStateEvent;if(e)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),n&&document.documentElement.classList.add("is-popstate");const i=this.getAnimationPromises("out");return Promise.all(i).then(()=>{this.triggerEvent("animationOutDone")}),i};function R(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function A(t){const{url:e,event:r,customTransition:a,history:l="push"}=null!=t?t:{},c=r instanceof PopStateEvent,u=this.shouldSkipTransition({url:e,event:r});this.triggerEvent("transitionStart",r),this.updateTransition(i(),e,a),null!=a&&document.documentElement.classList.add(`to-${n(a)}`);const h=this.leavePage({event:r,skipTransition:u}),d=this.fetchPage(t);if(!c){const t=e+(this.scrollToElement||"");"replace"===l?o(t):s(t)}this.currentPageUrl=i(),Promise.all([d,...h]).then(([t])=>{this.renderPage(t,{event:r,skipTransition:u})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const $=function({blocks:t,title:e}){return t.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=e,Promise.resolve()};function _(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function I(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function x(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const O=function(t){var e;if(null==(e=t)?void 0:e.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function q(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function D(t){return this.plugins.find(e=>e===t||e.name===t)}const M=function(t,{event:n,skipTransition:s}={}){if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(i(),t.url))return;const{url:r}=g.fromUrl(t.responseURL);this.isSameResolvedUrl(i(),r)||(this.cache.cacheUrl(e({},t,{url:r})),this.currentPageUrl=i(),o(r)),s||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",n),this.replaceContent(t).then(()=>{this.triggerEvent("contentReplaced",n),this.triggerEvent("pageView",n),this.options.cache||this.cache.empty(),this.enterPage({event:n,skipTransition:s}),this.scrollToElement=null})};function N(t,e,n){this.transition={from:t,to:e,custom:n}}function W({event:t}){return!(!(t instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}class V{constructor(t={}){this.version="3.1.1",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=i(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=R,this.performPageLoad=A,this.leavePage=H,this.renderPage=M,this.replaceContent=$,this.enterPage=E,this.triggerEvent=x,this.delegateEvent=r,this.on=_,this.off=I,this.updateTransition=N,this.shouldSkipTransition=W,this.getAnimationPromises=k,this.getPageData=C,this.fetchPage=T,this.getAnchorElement=P,this.log=()=>{},this.use=O,this.unuse=q,this.findPlugin=D,this.getCurrentUrl=i,this.cleanupAnimationClasses=v,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:(t,{el:e}={})=>!(null==e||!e.closest("[data-no-swup]")),linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>{var e;return"swup"!==(null==(e=t.state)?void 0:e.source)}},this.options=e({},this.defaults,t),this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new w(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=r(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),m(document.documentElement,this.options.containers),this.options.plugins.forEach(t=>this.use(t)),o(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),l("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,{el:e,event:n}={}){const{origin:i,url:s,hash:o}=g.fromUrl(t);return i!==window.location.origin||!(!e||!this.triggerWillOpenNewWindow(e))||!!this.options.ignoreVisit(s+o,{el:e,event:n})}linkClickHandler(t){const e=t.delegateTarget,{href:n,url:s,hash:o}=g.fromElement(e);if(this.shouldIgnoreVisit(n,{el:e,event:t}))return;if(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return void this.triggerEvent("openPageInNewTab",t);if(0!==t.button)return;if(this.triggerEvent("clickLink",t),t.preventDefault(),!s||s===i())return void this.handleLinkToSamePage(s,o,t);if(this.isSameResolvedUrl(s,i()))return;this.scrollToElement=o||null;const r=e.getAttribute("data-swup-transition")||void 0;let a;const l=e.getAttribute("data-swup-history");l&&["push","replace"].includes(l)&&(a=l),this.performPageLoad({url:s,customTransition:r,history:a})}handleLinkToSamePage(t,e,n){if(e){if(this.triggerEvent("samePageWithHash",n),!P(e))return console.warn(`Element for offset not found (#${e})`);o(t+e)}else this.triggerEvent("samePage",n)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(t){var e,n;if(this.options.skipPopStateHandling(t))return;if(this.isSameResolvedUrl(i(),this.currentPageUrl))return;const s=null!=(e=null==(n=t.state)?void 0:n.url)?e:location.href;if(this.shouldIgnoreVisit(s,{event:t}))return;const{url:o,hash:r}=g.fromUrl(s);r?this.scrollToElement=r:t.preventDefault(),this.triggerEvent("popState",t),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),v()),this.performPageLoad({url:o,event:t})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}export{g as Location,n as classify,v as cleanupAnimationClasses,s as createHistoryRecord,V as default,r as delegateEvent,u as escapeCssIdentifier,p as fetch,i as getCurrentUrl,d as getDataFromHtml,m as markSwupElements,c as nextTick,a as query,l as queryAll,h as toMs,o as updateHistoryRecord};
import t from"delegate-it";function e(){return e=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t},e.apply(this,arguments)}const n=(t,e)=>String(t).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||e||"",i=({hash:t}={})=>location.pathname+location.search+(t?location.hash:""),s=(t,n={})=>{const s=e({url:t=t||i({hash:!0}),random:Math.random(),source:"swup"},n);history.pushState(s,"",t)},o=(t=null,n={})=>{t=t||i({hash:!0});const s=e({},history.state,{url:t,random:Math.random(),source:"swup"},n);history.replaceState(s,"",t)},r=["base"],a=(e,n,i,s={})=>{let{base:o=document}=s,a=function(t,e){if(null==t)return{};var n,i,s={},o=Object.keys(t);for(i=0;i<o.length;i++)e.indexOf(n=o[i])>=0||(s[n]=t[n]);return s}(s,r);const l=t(o,e,n,i,a);return{destroy:()=>l.destroy()}},l=(t,e=document)=>e.querySelector(t),u=(t,e=document)=>Array.from(e.querySelectorAll(t)),c=t=>{requestAnimationFrame(()=>{requestAnimationFrame(()=>{t()})})},h=t=>window.CSS&&window.CSS.escape?CSS.escape(t):t,d=t=>1e3*Number(t.slice(0,-1).replace(",",".")),p=(t,e)=>{var n,i;let s=document.createElement("html");s.innerHTML=t;let o=[];e.forEach(t=>{if(null==l(t,s))return console.warn(`[swup] Container ${t} not found on page.`),null;u(t).length!==u(t,s).length&&console.warn("[swup] Mismatched number of containers found on new page."),u(t).forEach((e,n)=>{u(t,s)[n].setAttribute("data-swup",String(o.length)),o.push(u(t,s)[n].outerHTML)})});const r=(null==(n=l("title",s))?void 0:n.innerText)||"",a=null==(i=l("body",s))?void 0:i.className;return s.innerHTML="",s=null,{title:r,pageClass:a,blocks:o,originalContent:t}},g=(t,n)=>{const i={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:s,method:o,headers:r,data:a}=e({},i,t),l=new XMLHttpRequest;return l.onreadystatechange=function(){4===l.readyState&&n(l)},l.open(o,s,!0),Object.entries(r).forEach(([t,e])=>{l.setRequestHeader(t,e)}),l.send(a),l};class m extends URL{constructor(t,e=document.baseURI){super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new m(e)}static fromUrl(t){return new m(t)}}const f=(t,e)=>{let n=0;e.forEach(e=>{null==l(e,t)?console.warn(`[swup] Container ${e} not found on page.`):u(e).forEach((i,s)=>{u(e,t)[s].setAttribute("data-swup",String(n)),n++})})},v=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),w=()=>{const t=document.documentElement.className.split(" ").filter(v);document.documentElement.classList.remove(...t)};class E{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(m.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(i())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const P=function({event:t,skipTransition:e}={}){if(e)return this.triggerEvent("transitionEnd",t),this.cleanupAnimationClasses(),[Promise.resolve()];c(()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")});const n=this.getAnimationPromises("in");return Promise.all(n).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",t),this.cleanupAnimationClasses()}),n},S=t=>t?("#"===t.charAt(0)&&(t=t.substring(1)),t=decodeURIComponent(t),t=h(t),l(`#${t}`)||l(`a[name='${t}']`)):null;let b="transition",k="transitionend",U="animation",y="animationend";function L(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=u(e,document.body);return n.length?n.map(t=>function(t,e,n=null){const{type:i,timeout:s,propCount:o}=function(t,e=null){const n=window.getComputedStyle(t),i=`${b}Duration`,s=`${U}Delay`,o=`${U}Duration`,r=n[`${b}Delay`].split(", "),a=(n[i]||"").split(", "),l=C(r,a),u=(n[s]||"").split(", "),c=(n[o]||"").split(", "),h=C(u,c);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=c.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:c.length:0),{type:d,timeout:p,propCount:g}}(t,n);return i&&s?new Promise(e=>{const n="transition"===i?k:y,r=performance.now();let a=0;const l=()=>{t.removeEventListener(n,u),e()},u=e=>{if(e.target===t){if(!(t=>!!t.elapsedTime)(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=o&&l()}};setTimeout(()=>{a<o&&l()},s+1),t.addEventListener(n,u)}):(console.warn(`[swup] No CSS transition duration defined for element of selector ${e}`),Promise.resolve())}(t,e)):(console.warn(`[swup] No animated elements found by selector ${e}`),[Promise.resolve()])}function C(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>d(e)+d(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(b="WebkitTransition",k="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(U="WebkitAnimation",y="webkitAnimationEnd");const T=function(t){const n=p(t.responseText,this.options.containers);return n?e({},n,{responseURL:t.responseURL||window.location.href}):(console.warn("[swup] Received page is invalid."),null)};function H(t){const n=this.options.requestHeaders,{url:i}=t;return this.cache.exists(i)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(i))):new Promise((s,o)=>{g(e({},t,{headers:n}),t=>{if(500===t.status)return this.triggerEvent("serverError"),void o(i);const n=this.getPageData(t);if(!n||!n.blocks.length)return void o(i);const r=e({},n,{url:i});this.cache.cacheUrl(r),this.triggerEvent("pageLoaded"),s(r)})})}const R=function({event:t,skipTransition:e}={}){const n=t instanceof PopStateEvent;if(e)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),n&&document.documentElement.classList.add("is-popstate");const i=this.getAnimationPromises("out");return Promise.all(i).then(()=>{this.triggerEvent("animationOutDone")}),i};function A(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function $(t){const{url:e,event:o,customTransition:r}=null!=t?t:{},a=o instanceof PopStateEvent,l=this.shouldSkipTransition({url:e,event:o});this.triggerEvent("transitionStart",o),this.updateTransition(i(),e,r),null!=r&&document.documentElement.classList.add(`to-${n(r)}`);const u=this.leavePage({event:o,skipTransition:l}),c=this.fetchPage(t);a||s(e+(this.scrollToElement||"")),this.currentPageUrl=i(),Promise.all([c,...u]).then(([t])=>{this.renderPage(t,{event:o,skipTransition:l})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const _=function({blocks:t,title:e}){return t.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=e,Promise.resolve()};function O(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function x(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function q(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const D=function(t){var e;if(null==(e=t)?void 0:e.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function I(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function M(t){return this.plugins.find(e=>e===t||e.name===t)}const N=function(t,{event:n,skipTransition:s}={}){if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(i(),t.url))return;const{url:r}=m.fromUrl(t.responseURL);this.isSameResolvedUrl(i(),r)||(this.cache.cacheUrl(e({},t,{url:r})),this.currentPageUrl=i(),o(r)),s||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",n),this.replaceContent(t).then(()=>{this.triggerEvent("contentReplaced",n),this.triggerEvent("pageView",n),this.options.cache||this.cache.empty(),this.enterPage({event:n,skipTransition:s}),this.scrollToElement=null})};function W(t,e,n){this.transition={from:t,to:e,custom:n}}function V({event:t}){return!(!(t instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}class j{constructor(t={}){this.version="3.0.4",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=i(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=A,this.performPageLoad=$,this.leavePage=R,this.renderPage=N,this.replaceContent=_,this.enterPage=P,this.triggerEvent=q,this.delegateEvent=a,this.on=O,this.off=x,this.updateTransition=W,this.shouldSkipTransition=V,this.getAnimationPromises=L,this.getPageData=T,this.fetchPage=H,this.getAnchorElement=S,this.log=()=>{},this.use=D,this.unuse=I,this.findPlugin=M,this.getCurrentUrl=i,this.cleanupAnimationClasses=w,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:(t,{el:e}={})=>!(null==e||!e.closest("[data-no-swup]")),linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>{var e;return"swup"!==(null==(e=t.state)?void 0:e.source)}},this.options=e({},this.defaults,t),this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new E(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=a(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),f(document.documentElement,this.options.containers),this.options.plugins.forEach(t=>this.use(t)),o(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),u("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,{el:e}={}){const{origin:n,url:i,hash:s}=m.fromUrl(t);return n!==window.location.origin||!(!e||!this.triggerWillOpenNewWindow(e))||!!this.options.ignoreVisit(i+s,{el:e})}linkClickHandler(t){const e=t.delegateTarget,{href:n,url:s,hash:o}=m.fromElement(e);if(this.shouldIgnoreVisit(n,{el:e}))return;if(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return void this.triggerEvent("openPageInNewTab",t);if(0!==t.button)return;if(this.triggerEvent("clickLink",t),t.preventDefault(),!s||s===i())return void this.handleLinkToSamePage(s,o,t);if(this.isSameResolvedUrl(s,i()))return;this.scrollToElement=o||null;const r=e.getAttribute("data-swup-transition")||void 0;this.performPageLoad({url:s,customTransition:r})}handleLinkToSamePage(t,e,n){if(e){if(this.triggerEvent("samePageWithHash",n),!S(e))return console.warn(`Element for offset not found (#${e})`);o(t+e)}else this.triggerEvent("samePage",n)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(t){var e,n;if(this.options.skipPopStateHandling(t))return;if(this.isSameResolvedUrl(i(),this.currentPageUrl))return;const s=null!=(e=null==(n=t.state)?void 0:n.url)?e:location.href;if(this.shouldIgnoreVisit(s))return;const{url:o,hash:r}=m.fromUrl(s);r?this.scrollToElement=r:t.preventDefault(),this.triggerEvent("popState",t),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),w()),this.performPageLoad({url:o,event:t})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}export{m as Location,n as classify,w as cleanupAnimationClasses,s as createHistoryRecord,j as default,a as delegateEvent,h as escapeCssIdentifier,g as fetch,i as getCurrentUrl,p as getDataFromHtml,f as markSwupElements,c as nextTick,l as query,u as queryAll,d as toMs,o as updateHistoryRecord};
//# sourceMappingURL=Swup.modern.js.map

@@ -1,2 +0,2 @@

import t from"delegate-it";const e=(t,e)=>String(t).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||e||"",n=function(t){let{hash:e}=void 0===t?{}:t;return location.pathname+location.search+(e?location.hash:"")},i=function(t,e){void 0===e&&(e={});const i={url:t=t||n({hash:!0}),random:Math.random(),source:"swup",...e};history.pushState(i,"",t)},s=function(t,e){void 0===t&&(t=null),void 0===e&&(e={}),t=t||n({hash:!0});const i={...history.state,url:t,random:Math.random(),source:"swup",...e};history.replaceState(i,"",t)},o=(e,n,i,s)=>{const o=new AbortController;return t(e,n,i,s),{destroy:()=>o.abort()}},r=function(t,e){return void 0===e&&(e=document),e.querySelector(t)},a=function(t,e){return void 0===e&&(e=document),Array.from(e.querySelectorAll(t))},l=t=>{requestAnimationFrame(()=>{requestAnimationFrame(()=>{t()})})},c=t=>window.CSS&&window.CSS.escape?CSS.escape(t):t,u=t=>1e3*Number(t.slice(0,-1).replace(",",".")),h=(t,e)=>{let n=document.createElement("html");n.innerHTML=t;let i=[];e.forEach(t=>{if(null==r(t,n))return console.warn(`[swup] Container ${t} not found on page.`),null;a(t).length!==a(t,n).length&&console.warn("[swup] Mismatched number of containers found on new page."),a(t).forEach((e,s)=>{a(t,n)[s].setAttribute("data-swup",String(i.length)),i.push(a(t,n)[s].outerHTML)})});const s=r("title",n)?.innerText||"",o=r("body",n)?.className;return n.innerHTML="",n=null,{title:s,pageClass:o,blocks:i,originalContent:t}},d=(t,e)=>{const n={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:i,method:s,headers:o,data:r}={...n,...t},a=new XMLHttpRequest;return a.onreadystatechange=function(){4===a.readyState&&e(a)},a.open(s,i,!0),Object.entries(o).forEach(t=>{let[e,n]=t;a.setRequestHeader(e,n)}),a.send(r),a};class p extends URL{constructor(t,e){void 0===e&&(e=document.baseURI),super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new p(e)}static fromUrl(t){return new p(t)}}const g=(t,e)=>{let n=0;e.forEach(e=>{null==r(e,t)?console.warn(`[swup] Container ${e} not found on page.`):a(e).forEach((i,s)=>{a(e,t)[s].setAttribute("data-swup",String(n)),n++})})},m=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),f=()=>{const t=document.documentElement.className.split(" ").filter(m);document.documentElement.classList.remove(...t)};class v{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(p.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(n())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const w=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;if(n)return this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses(),[Promise.resolve()];l(()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")});const i=this.getAnimationPromises("in");return Promise.all(i).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses()}),i},E=t=>{if(t&&"#"===t.charAt(0)&&(t=t.substring(1)),!t)return null;const e=decodeURIComponent(t);let n=document.getElementById(t)||document.getElementById(e)||r(`a[name='${c(t)}']`)||r(`a[name='${c(e)}']`);return n||"top"!==t||(n=document.body),n};let P="transition",S="transitionend",b="animation",U="animationend";function k(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=a(e,document.body);if(!n.length)return console.warn(`[swup] No elements found matching animationSelector \`${e}\``),[Promise.resolve()];const i=n.map(t=>function(t){const{type:e,timeout:n,propCount:i}=function(t,e){void 0===e&&(e=null);const n=window.getComputedStyle(t),i=`${P}Duration`,s=`${b}Delay`,o=`${b}Duration`,r=n[`${P}Delay`].split(", "),a=(n[i]||"").split(", "),l=y(r,a),c=(n[s]||"").split(", "),u=(n[o]||"").split(", "),h=y(c,u);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=u.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:u.length:0),{type:d,timeout:p,propCount:g}}(t);if(e&&n)return new Promise(s=>{const o="transition"===e?S:U,r=performance.now();let a=0;const l=()=>{t.removeEventListener(o,c),s()},c=e=>{if(e.target===t){if(!(t=>[S,U].includes(t.type))(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=i&&l()}};setTimeout(()=>{a<i&&l()},n+1),t.addEventListener(o,c)})}(t)).filter(Boolean);return i.length?i:(console.warn(`[swup] No CSS animation duration defined on elements matching \`${e}\``),[Promise.resolve()])}function y(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>u(e)+u(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(P="WebkitTransition",S="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(b="WebkitAnimation",U="webkitAnimationEnd");const L=function(t){const e=h(t.responseText,this.options.containers);return e?{...e,responseURL:t.responseURL||window.location.href}:(console.warn("[swup] Received page is invalid."),null)};function C(t){const e=this.options.requestHeaders,{url:n}=t;return this.cache.exists(n)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(n))):new Promise((i,s)=>{d({...t,headers:e},t=>{if(500===t.status)return this.triggerEvent("serverError"),void s(n);const e=this.getPageData(t);if(!e||!e.blocks.length)return void s(n);const o={...e,url:n};this.cache.cacheUrl(o),this.triggerEvent("pageLoaded"),i(o)})})}const T=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;const i=e instanceof PopStateEvent;if(n)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),i&&document.documentElement.classList.add("is-popstate");const s=this.getAnimationPromises("out");return Promise.all(s).then(()=>{this.triggerEvent("animationOutDone")}),s};function H(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function R(t){const{url:o,event:r,customTransition:a,history:l="push"}=t??{},c=r instanceof PopStateEvent,u=this.shouldSkipTransition({url:o,event:r});this.triggerEvent("transitionStart",r),this.updateTransition(n(),o,a),null!=a&&document.documentElement.classList.add(`to-${e(a)}`);const h=this.leavePage({event:r,skipTransition:u}),d=this.fetchPage(t);if(!c){const t=o+(this.scrollToElement||"");"replace"===l?s(t):i(t)}this.currentPageUrl=n(),Promise.all([d,...h]).then(t=>{let[e]=t;this.renderPage(e,{event:r,skipTransition:u})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const A=function(t){let{blocks:e,title:n}=t;return e.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=n,Promise.resolve()};function $(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function _(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function I(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const x=function(t){if(t?.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function q(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function D(t){return this.plugins.find(e=>e===t||e.name===t)}const M=function(t,e){let{event:i,skipTransition:o}=void 0===e?{}:e;if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(n(),t.url))return;const{url:r}=p.fromUrl(t.responseURL);this.isSameResolvedUrl(n(),r)||(this.cache.cacheUrl({...t,url:r}),this.currentPageUrl=n(),s(r)),o||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",i),this.replaceContent(t).then(()=>{this.triggerEvent("contentReplaced",i),this.triggerEvent("pageView",i),this.options.cache||this.cache.empty(),this.enterPage({event:i,skipTransition:o}),this.scrollToElement=null})};function N(t,e,n){this.transition={from:t,to:e,custom:n}}function W(t){let{event:e}=t;return!(!(e instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}class O{constructor(t){void 0===t&&(t={}),this.version="3.1.1",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=n(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=H,this.performPageLoad=R,this.leavePage=T,this.renderPage=M,this.replaceContent=A,this.enterPage=w,this.triggerEvent=I,this.delegateEvent=o,this.on=$,this.off=_,this.updateTransition=N,this.shouldSkipTransition=W,this.getAnimationPromises=k,this.getPageData=L,this.fetchPage=C,this.getAnchorElement=E,this.log=()=>{},this.use=x,this.unuse=q,this.findPlugin=D,this.getCurrentUrl=n,this.cleanupAnimationClasses=f,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:function(t,e){let{el:n}=void 0===e?{}:e;return!!n?.closest("[data-no-swup]")},linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>"swup"!==t.state?.source},this.options={...this.defaults,...t},this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new v(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=o(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),g(document.documentElement,this.options.containers),this.options.plugins.forEach(t=>this.use(t)),s(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),a("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,e){let{el:n,event:i}=void 0===e?{}:e;const{origin:s,url:o,hash:r}=p.fromUrl(t);return s!==window.location.origin||!(!n||!this.triggerWillOpenNewWindow(n))||!!this.options.ignoreVisit(o+r,{el:n,event:i})}linkClickHandler(t){const e=t.delegateTarget,{href:i,url:s,hash:o}=p.fromElement(e);if(this.shouldIgnoreVisit(i,{el:e,event:t}))return;if(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return void this.triggerEvent("openPageInNewTab",t);if(0!==t.button)return;if(this.triggerEvent("clickLink",t),t.preventDefault(),!s||s===n())return void this.handleLinkToSamePage(s,o,t);if(this.isSameResolvedUrl(s,n()))return;this.scrollToElement=o||null;const r=e.getAttribute("data-swup-transition")||void 0;let a;const l=e.getAttribute("data-swup-history");l&&["push","replace"].includes(l)&&(a=l),this.performPageLoad({url:s,customTransition:r,history:a})}handleLinkToSamePage(t,e,n){if(e){if(this.triggerEvent("samePageWithHash",n),!E(e))return console.warn(`Element for offset not found (#${e})`);s(t+e)}else this.triggerEvent("samePage",n)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(t){if(this.options.skipPopStateHandling(t))return;if(this.isSameResolvedUrl(n(),this.currentPageUrl))return;const e=t.state?.url??location.href;if(this.shouldIgnoreVisit(e,{event:t}))return;const{url:i,hash:s}=p.fromUrl(e);s?this.scrollToElement=s:t.preventDefault(),this.triggerEvent("popState",t),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),f()),this.performPageLoad({url:i,event:t})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}export{p as Location,e as classify,f as cleanupAnimationClasses,i as createHistoryRecord,O as default,o as delegateEvent,c as escapeCssIdentifier,d as fetch,n as getCurrentUrl,h as getDataFromHtml,g as markSwupElements,l as nextTick,r as query,a as queryAll,u as toMs,s as updateHistoryRecord};
import t from"delegate-it";const e=(t,e)=>String(t).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||e||"",n=function(t){let{hash:e}=void 0===t?{}:t;return location.pathname+location.search+(e?location.hash:"")},i=function(t,e){void 0===e&&(e={});const i={url:t=t||n({hash:!0}),random:Math.random(),source:"swup",...e};history.pushState(i,"",t)},s=function(t,e){void 0===t&&(t=null),void 0===e&&(e={}),t=t||n({hash:!0});const i={...history.state,url:t,random:Math.random(),source:"swup",...e};history.replaceState(i,"",t)},o=function(e,n,i,s){let{base:o=document,...r}=void 0===s?{}:s;const a=t(o,e,n,i,r);return{destroy:()=>a.destroy()}},r=function(t,e){return void 0===e&&(e=document),e.querySelector(t)},a=function(t,e){return void 0===e&&(e=document),Array.from(e.querySelectorAll(t))},l=t=>{requestAnimationFrame(()=>{requestAnimationFrame(()=>{t()})})},c=t=>window.CSS&&window.CSS.escape?CSS.escape(t):t,u=t=>1e3*Number(t.slice(0,-1).replace(",",".")),h=(t,e)=>{let n=document.createElement("html");n.innerHTML=t;let i=[];e.forEach(t=>{if(null==r(t,n))return console.warn(`[swup] Container ${t} not found on page.`),null;a(t).length!==a(t,n).length&&console.warn("[swup] Mismatched number of containers found on new page."),a(t).forEach((e,s)=>{a(t,n)[s].setAttribute("data-swup",String(i.length)),i.push(a(t,n)[s].outerHTML)})});const s=r("title",n)?.innerText||"",o=r("body",n)?.className;return n.innerHTML="",n=null,{title:s,pageClass:o,blocks:i,originalContent:t}},d=(t,e)=>{const n={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:i,method:s,headers:o,data:r}={...n,...t},a=new XMLHttpRequest;return a.onreadystatechange=function(){4===a.readyState&&e(a)},a.open(s,i,!0),Object.entries(o).forEach(t=>{let[e,n]=t;a.setRequestHeader(e,n)}),a.send(r),a};class p extends URL{constructor(t,e){void 0===e&&(e=document.baseURI),super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new p(e)}static fromUrl(t){return new p(t)}}const g=(t,e)=>{let n=0;e.forEach(e=>{null==r(e,t)?console.warn(`[swup] Container ${e} not found on page.`):a(e).forEach((i,s)=>{a(e,t)[s].setAttribute("data-swup",String(n)),n++})})},m=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),f=()=>{const t=document.documentElement.className.split(" ").filter(m);document.documentElement.classList.remove(...t)};class v{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(p.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(n())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const w=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;if(n)return this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses(),[Promise.resolve()];l(()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")});const i=this.getAnimationPromises("in");return Promise.all(i).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses()}),i},E=t=>t?("#"===t.charAt(0)&&(t=t.substring(1)),t=decodeURIComponent(t),t=c(t),r(`#${t}`)||r(`a[name='${t}']`)):null;let P="transition",S="transitionend",b="animation",U="animationend";function k(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=a(e,document.body);return n.length?n.map(t=>function(t,e,n){void 0===n&&(n=null);const{type:i,timeout:s,propCount:o}=function(t,e){void 0===e&&(e=null);const n=window.getComputedStyle(t),i=`${P}Duration`,s=`${b}Delay`,o=`${b}Duration`,r=n[`${P}Delay`].split(", "),a=(n[i]||"").split(", "),l=y(r,a),c=(n[s]||"").split(", "),u=(n[o]||"").split(", "),h=y(c,u);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=u.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:u.length:0),{type:d,timeout:p,propCount:g}}(t,n);return i&&s?new Promise(e=>{const n="transition"===i?S:U,r=performance.now();let a=0;const l=()=>{t.removeEventListener(n,c),e()},c=e=>{if(e.target===t){if(!(t=>!!t.elapsedTime)(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=o&&l()}};setTimeout(()=>{a<o&&l()},s+1),t.addEventListener(n,c)}):(console.warn(`[swup] No CSS transition duration defined for element of selector ${e}`),Promise.resolve())}(t,e)):(console.warn(`[swup] No animated elements found by selector ${e}`),[Promise.resolve()])}function y(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>u(e)+u(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(P="WebkitTransition",S="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(b="WebkitAnimation",U="webkitAnimationEnd");const L=function(t){const e=h(t.responseText,this.options.containers);return e?{...e,responseURL:t.responseURL||window.location.href}:(console.warn("[swup] Received page is invalid."),null)};function C(t){const e=this.options.requestHeaders,{url:n}=t;return this.cache.exists(n)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(n))):new Promise((i,s)=>{d({...t,headers:e},t=>{if(500===t.status)return this.triggerEvent("serverError"),void s(n);const e=this.getPageData(t);if(!e||!e.blocks.length)return void s(n);const o={...e,url:n};this.cache.cacheUrl(o),this.triggerEvent("pageLoaded"),i(o)})})}const T=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;const i=e instanceof PopStateEvent;if(n)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),i&&document.documentElement.classList.add("is-popstate");const s=this.getAnimationPromises("out");return Promise.all(s).then(()=>{this.triggerEvent("animationOutDone")}),s};function H(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function R(t){const{url:s,event:o,customTransition:r}=t??{},a=o instanceof PopStateEvent,l=this.shouldSkipTransition({url:s,event:o});this.triggerEvent("transitionStart",o),this.updateTransition(n(),s,r),null!=r&&document.documentElement.classList.add(`to-${e(r)}`);const c=this.leavePage({event:o,skipTransition:l}),u=this.fetchPage(t);a||i(s+(this.scrollToElement||"")),this.currentPageUrl=n(),Promise.all([u,...c]).then(t=>{let[e]=t;this.renderPage(e,{event:o,skipTransition:l})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const A=function(t){let{blocks:e,title:n}=t;return e.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=n,Promise.resolve()};function $(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function _(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function x(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const q=function(t){if(t?.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function D(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function I(t){return this.plugins.find(e=>e===t||e.name===t)}const M=function(t,e){let{event:i,skipTransition:o}=void 0===e?{}:e;if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(n(),t.url))return;const{url:r}=p.fromUrl(t.responseURL);this.isSameResolvedUrl(n(),r)||(this.cache.cacheUrl({...t,url:r}),this.currentPageUrl=n(),s(r)),o||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",i),this.replaceContent(t).then(()=>{this.triggerEvent("contentReplaced",i),this.triggerEvent("pageView",i),this.options.cache||this.cache.empty(),this.enterPage({event:i,skipTransition:o}),this.scrollToElement=null})};function N(t,e,n){this.transition={from:t,to:e,custom:n}}function W(t){let{event:e}=t;return!(!(e instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}class O{constructor(t){void 0===t&&(t={}),this.version="3.0.4",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=n(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=H,this.performPageLoad=R,this.leavePage=T,this.renderPage=M,this.replaceContent=A,this.enterPage=w,this.triggerEvent=x,this.delegateEvent=o,this.on=$,this.off=_,this.updateTransition=N,this.shouldSkipTransition=W,this.getAnimationPromises=k,this.getPageData=L,this.fetchPage=C,this.getAnchorElement=E,this.log=()=>{},this.use=q,this.unuse=D,this.findPlugin=I,this.getCurrentUrl=n,this.cleanupAnimationClasses=f,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:function(t,e){let{el:n}=void 0===e?{}:e;return!!n?.closest("[data-no-swup]")},linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>"swup"!==t.state?.source},this.options={...this.defaults,...t},this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new v(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=o(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),g(document.documentElement,this.options.containers),this.options.plugins.forEach(t=>this.use(t)),s(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),a("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,e){let{el:n}=void 0===e?{}:e;const{origin:i,url:s,hash:o}=p.fromUrl(t);return i!==window.location.origin||!(!n||!this.triggerWillOpenNewWindow(n))||!!this.options.ignoreVisit(s+o,{el:n})}linkClickHandler(t){const e=t.delegateTarget,{href:i,url:s,hash:o}=p.fromElement(e);if(this.shouldIgnoreVisit(i,{el:e}))return;if(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return void this.triggerEvent("openPageInNewTab",t);if(0!==t.button)return;if(this.triggerEvent("clickLink",t),t.preventDefault(),!s||s===n())return void this.handleLinkToSamePage(s,o,t);if(this.isSameResolvedUrl(s,n()))return;this.scrollToElement=o||null;const r=e.getAttribute("data-swup-transition")||void 0;this.performPageLoad({url:s,customTransition:r})}handleLinkToSamePage(t,e,n){if(e){if(this.triggerEvent("samePageWithHash",n),!E(e))return console.warn(`Element for offset not found (#${e})`);s(t+e)}else this.triggerEvent("samePage",n)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(t){if(this.options.skipPopStateHandling(t))return;if(this.isSameResolvedUrl(n(),this.currentPageUrl))return;const e=t.state?.url??location.href;if(this.shouldIgnoreVisit(e))return;const{url:i,hash:s}=p.fromUrl(e);s?this.scrollToElement=s:t.preventDefault(),this.triggerEvent("popState",t),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),f()),this.performPageLoad({url:i,event:t})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}export{p as Location,e as classify,f as cleanupAnimationClasses,i as createHistoryRecord,O as default,o as delegateEvent,c as escapeCssIdentifier,d as fetch,n as getCurrentUrl,h as getDataFromHtml,g as markSwupElements,l as nextTick,r as query,a as queryAll,u as toMs,s as updateHistoryRecord};
//# sourceMappingURL=Swup.module.js.map

@@ -1,2 +0,2 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t||self).Swup=e()}(this,function(){const t=function(t){let{hash:e}=void 0===t?{}:t;return location.pathname+location.search+(e?location.hash:"")},e=function(e,n){void 0===e&&(e=null),void 0===n&&(n={}),e=e||t({hash:!0});const i={...history.state,url:e,random:Math.random(),source:"swup",...n};history.replaceState(i,"",e)},n=new WeakMap;function i(t,e,i,s){if(!t&&!n.has(e))return!1;const o=n.get(e)??new WeakMap;n.set(e,o);const r=o.get(i)??new Set;o.set(i,r);const a=r.has(s);return t?r.add(s):r.delete(s),a&&t}const s=(t,e,n,s)=>{const o=new AbortController;return function(t,e,n,s={}){const{signal:o,base:r=document}=s;if(o?.aborted)return;const{once:a,...l}=s,c=r instanceof Document?r.documentElement:r,u=Boolean("object"==typeof s?s.capture:s),h=s=>{const o=function(t,e){let n=t.target;if(n instanceof Text&&(n=n.parentElement),n instanceof Element&&t.currentTarget instanceof Element){const i=n.closest(e);if(i&&t.currentTarget.contains(i))return i}}(s,t);if(o){const t=Object.assign(s,{delegateTarget:o});n.call(c,t),a&&(c.removeEventListener(e,h,l),i(!1,c,n,d))}},d=JSON.stringify({selector:t,type:e,capture:u});i(!0,c,n,d)||c.addEventListener(e,h,l),o?.addEventListener("abort",()=>{i(!1,c,n,d)})}(t,e,n,s),{destroy:()=>o.abort()}},o=function(t,e){return void 0===e&&(e=document),e.querySelector(t)},r=function(t,e){return void 0===e&&(e=document),Array.from(e.querySelectorAll(t))},a=t=>window.CSS&&window.CSS.escape?CSS.escape(t):t,l=t=>1e3*Number(t.slice(0,-1).replace(",","."));class c extends URL{constructor(t,e){void 0===e&&(e=document.baseURI),super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new c(e)}static fromUrl(t){return new c(t)}}const u=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),h=()=>{const t=document.documentElement.className.split(" ").filter(u);document.documentElement.classList.remove(...t)};class d{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(c.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(t())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const p=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;if(n)return this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses(),[Promise.resolve()];var i;i=()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")},requestAnimationFrame(()=>{requestAnimationFrame(()=>{i()})});const s=this.getAnimationPromises("in");return Promise.all(s).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses()}),s},g=t=>{if(t&&"#"===t.charAt(0)&&(t=t.substring(1)),!t)return null;const e=decodeURIComponent(t);let n=document.getElementById(t)||document.getElementById(e)||o(`a[name='${a(t)}']`)||o(`a[name='${a(e)}']`);return n||"top"!==t||(n=document.body),n};let m="transition",f="transitionend",v="animation",w="animationend";function E(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=r(e,document.body);if(!n.length)return console.warn(`[swup] No elements found matching animationSelector \`${e}\``),[Promise.resolve()];const i=n.map(t=>function(t){const{type:e,timeout:n,propCount:i}=function(t,e){void 0===e&&(e=null);const n=window.getComputedStyle(t),i=`${m}Duration`,s=`${v}Delay`,o=`${v}Duration`,r=n[`${m}Delay`].split(", "),a=(n[i]||"").split(", "),l=P(r,a),c=(n[s]||"").split(", "),u=(n[o]||"").split(", "),h=P(c,u);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=u.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:u.length:0),{type:d,timeout:p,propCount:g}}(t);if(e&&n)return new Promise(s=>{const o="transition"===e?f:w,r=performance.now();let a=0;const l=()=>{t.removeEventListener(o,c),s()},c=e=>{if(e.target===t){if(!(t=>[f,w].includes(t.type))(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=i&&l()}};setTimeout(()=>{a<i&&l()},n+1),t.addEventListener(o,c)})}(t)).filter(Boolean);return i.length?i:(console.warn(`[swup] No CSS animation duration defined on elements matching \`${e}\``),[Promise.resolve()])}function P(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>l(e)+l(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(m="WebkitTransition",f="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(v="WebkitAnimation",w="webkitAnimationEnd");const S=function(t){const e=((t,e)=>{let n=document.createElement("html");n.innerHTML=t;let i=[];e.forEach(t=>{if(null==o(t,n))return console.warn(`[swup] Container ${t} not found on page.`),null;r(t).length!==r(t,n).length&&console.warn("[swup] Mismatched number of containers found on new page."),r(t).forEach((e,s)=>{r(t,n)[s].setAttribute("data-swup",String(i.length)),i.push(r(t,n)[s].outerHTML)})});const s=o("title",n)?.innerText||"",a=o("body",n)?.className;return n.innerHTML="",n=null,{title:s,pageClass:a,blocks:i,originalContent:t}})(t.responseText,this.options.containers);return e?{...e,responseURL:t.responseURL||window.location.href}:(console.warn("[swup] Received page is invalid."),null)};function b(t){const e=this.options.requestHeaders,{url:n}=t;return this.cache.exists(n)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(n))):new Promise((i,s)=>{((t,e)=>{const n={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:i,method:s,headers:o,data:r}={...n,...t},a=new XMLHttpRequest;a.onreadystatechange=function(){4===a.readyState&&e(a)},a.open(s,i,!0),Object.entries(o).forEach(t=>{let[e,n]=t;a.setRequestHeader(e,n)}),a.send(r)})({...t,headers:e},t=>{if(500===t.status)return this.triggerEvent("serverError"),void s(n);const e=this.getPageData(t);if(!e||!e.blocks.length)return void s(n);const o={...e,url:n};this.cache.cacheUrl(o),this.triggerEvent("pageLoaded"),i(o)})})}const y=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;const i=e instanceof PopStateEvent;if(n)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),i&&document.documentElement.classList.add("is-popstate");const s=this.getAnimationPromises("out");return Promise.all(s).then(()=>{this.triggerEvent("animationOutDone")}),s};function k(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function U(n){const{url:i,event:s,customTransition:o,history:r="push"}=n??{},a=s instanceof PopStateEvent,l=this.shouldSkipTransition({url:i,event:s});var c;this.triggerEvent("transitionStart",s),this.updateTransition(t(),i,o),null!=o&&document.documentElement.classList.add(`to-${c=o,String(c).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||""}`);const u=this.leavePage({event:s,skipTransition:l}),h=this.fetchPage(n);if(!a){const n=i+(this.scrollToElement||"");"replace"===r?e(n):function(e,n){void 0===n&&(n={});const i={url:e=e||t({hash:!0}),random:Math.random(),source:"swup",...n};history.pushState(i,"",e)}(n)}this.currentPageUrl=t(),Promise.all([h,...u]).then(t=>{let[e]=t;this.renderPage(e,{event:s,skipTransition:l})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const L=function(t){let{blocks:e,title:n}=t;return e.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=n,Promise.resolve()};function T(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function C(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function H(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const R=function(t){if(t?.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function A(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function $(t){return this.plugins.find(e=>e===t||e.name===t)}const _=function(n,i){let{event:s,skipTransition:o}=void 0===i?{}:i;if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(t(),n.url))return;const{url:r}=c.fromUrl(n.responseURL);this.isSameResolvedUrl(t(),r)||(this.cache.cacheUrl({...n,url:r}),this.currentPageUrl=t(),e(r)),o||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",s),this.replaceContent(n).then(()=>{this.triggerEvent("contentReplaced",s),this.triggerEvent("pageView",s),this.options.cache||this.cache.empty(),this.enterPage({event:s,skipTransition:o}),this.scrollToElement=null})};function x(t,e,n){this.transition={from:t,to:e,custom:n}}function I(t){let{event:e}=t;return!(!(e instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}return class{constructor(e){void 0===e&&(e={}),this.version="3.1.1",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=t(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=k,this.performPageLoad=U,this.leavePage=y,this.renderPage=_,this.replaceContent=L,this.enterPage=p,this.triggerEvent=H,this.delegateEvent=s,this.on=T,this.off=C,this.updateTransition=x,this.shouldSkipTransition=I,this.getAnimationPromises=E,this.getPageData=S,this.fetchPage=b,this.getAnchorElement=g,this.log=()=>{},this.use=R,this.unuse=A,this.findPlugin=$,this.getCurrentUrl=t,this.cleanupAnimationClasses=h,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:function(t,e){let{el:n}=void 0===e?{}:e;return!!n?.closest("[data-no-swup]")},linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>"swup"!==t.state?.source},this.options={...this.defaults,...e},this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new d(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=s(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),((t,e)=>{let n=0;this.options.containers.forEach(e=>{null==o(e,t)?console.warn(`[swup] Container ${e} not found on page.`):r(e).forEach((i,s)=>{r(e,t)[s].setAttribute("data-swup",String(n)),n++})})})(document.documentElement),this.options.plugins.forEach(t=>this.use(t)),e(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),r("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,e){let{el:n,event:i}=void 0===e?{}:e;const{origin:s,url:o,hash:r}=c.fromUrl(t);return s!==window.location.origin||!(!n||!this.triggerWillOpenNewWindow(n))||!!this.options.ignoreVisit(o+r,{el:n,event:i})}linkClickHandler(e){const n=e.delegateTarget,{href:i,url:s,hash:o}=c.fromElement(n);if(this.shouldIgnoreVisit(i,{el:n,event:e}))return;if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return void this.triggerEvent("openPageInNewTab",e);if(0!==e.button)return;if(this.triggerEvent("clickLink",e),e.preventDefault(),!s||s===t())return void this.handleLinkToSamePage(s,o,e);if(this.isSameResolvedUrl(s,t()))return;this.scrollToElement=o||null;const r=n.getAttribute("data-swup-transition")||void 0;let a;const l=n.getAttribute("data-swup-history");l&&["push","replace"].includes(l)&&(a=l),this.performPageLoad({url:s,customTransition:r,history:a})}handleLinkToSamePage(t,n,i){if(n){if(this.triggerEvent("samePageWithHash",i),!g(n))return console.warn(`Element for offset not found (#${n})`);e(t+n)}else this.triggerEvent("samePage",i)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(e){if(this.options.skipPopStateHandling(e))return;if(this.isSameResolvedUrl(t(),this.currentPageUrl))return;const n=e.state?.url??location.href;if(this.shouldIgnoreVisit(n,{event:e}))return;const{url:i,hash:s}=c.fromUrl(n);s?this.scrollToElement=s:e.preventDefault(),this.triggerEvent("popState",e),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),h()),this.performPageLoad({url:i,event:e})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t||self).Swup=e()}(this,function(){const t=function(t){let{hash:e}=void 0===t?{}:t;return location.pathname+location.search+(e?location.hash:"")},e=function(e,n){void 0===e&&(e=null),void 0===n&&(n={}),e=e||t({hash:!0});const i={...history.state,url:e,random:Math.random(),source:"swup",...n};history.replaceState(i,"",e)},n=new WeakMap;function i(t,e,i,s){var o,r;if(!t&&!n.has(e))return!1;const a=null!==(o=n.get(e))&&void 0!==o?o:new WeakMap;if(n.set(e,a),!t&&!n.has(e))return!1;const l=null!==(r=a.get(i))&&void 0!==r?r:new Set;a.set(i,l);const c=l.has(s);return t?l.add(s):l.delete(s),c&&t}function s(t,e,n,o,r){if("string"==typeof t&&(t=document.querySelectorAll(t)),"function"!=typeof t.addEventListener){const i=Array.prototype.map.call(t,t=>s(t,e,n,o,r));return{destroy(){for(const t of i)t.destroy()}}}const a=t instanceof Document?t.documentElement:t,l=Boolean("object"==typeof r?r.capture:r),c=t=>{const n=function(t,e){let n=t.target;if(n instanceof Text&&(n=n.parentElement),n instanceof Element&&t.currentTarget instanceof Element){const i=n.closest(e);if(i&&t.currentTarget.contains(i))return i}}(t,e);n&&(t.delegateTarget=n,o.call(a,t))};"object"==typeof r&&delete r.once;const u=JSON.stringify({selector:e,type:n,capture:l}),h={destroy(){a.removeEventListener(n,c,r),i(!1,a,o,u)}};return i(!0,a,o,u)||a.addEventListener(n,c,r),h}const o=function(t,e,n,i){let{base:o=document,...r}=void 0===i?{}:i;const a=s(o,t,e,n,r);return{destroy:()=>a.destroy()}},r=function(t,e){return void 0===e&&(e=document),e.querySelector(t)},a=function(t,e){return void 0===e&&(e=document),Array.from(e.querySelectorAll(t))},l=t=>1e3*Number(t.slice(0,-1).replace(",","."));class c extends URL{constructor(t,e){void 0===e&&(e=document.baseURI),super(t.toString(),e)}get url(){return this.pathname+this.search}static fromElement(t){const e=t.getAttribute("href")||t.getAttribute("xlink:href");return new c(e)}static fromUrl(t){return new c(t)}}const u=t=>/^to-/.test(t)||["is-changing","is-rendering","is-popstate"].includes(t),h=()=>{const t=document.documentElement.className.split(" ").filter(u);document.documentElement.classList.remove(...t)};class d{constructor(t){this.pages={},this.last=null,this.swup=void 0,this.swup=t}getCacheUrl(t){return this.swup.resolveUrl(c.fromUrl(t).url)}cacheUrl(t){t.url=this.getCacheUrl(t.url),t.url in this.pages==0&&(this.pages[t.url]=t),t.responseURL=this.getCacheUrl(t.responseURL),this.last=this.pages[t.url],this.swup.log(`Cache (${Object.keys(this.pages).length})`,this.pages)}getPage(t){return t=this.getCacheUrl(t),this.pages[t]}getCurrentPage(){return this.getPage(t())}exists(t){return(t=this.getCacheUrl(t))in this.pages}empty(){this.pages={},this.last=null,this.swup.log("Cache cleared")}remove(t){delete this.pages[this.getCacheUrl(t)]}}const p=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;if(n)return this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses(),[Promise.resolve()];var i;i=()=>{this.triggerEvent("animationInStart"),document.documentElement.classList.remove("is-animating")},requestAnimationFrame(()=>{requestAnimationFrame(()=>{i()})});const s=this.getAnimationPromises("in");return Promise.all(s).then(()=>{this.triggerEvent("animationInDone"),this.triggerEvent("transitionEnd",e),this.cleanupAnimationClasses()}),s},g=t=>{return t?("#"===t.charAt(0)&&(t=t.substring(1)),e=t=decodeURIComponent(t),t=window.CSS&&window.CSS.escape?CSS.escape(e):e,r(`#${t}`)||r(`a[name='${t}']`)):null;var e};let m="transition",f="transitionend",v="animation",w="animationend";function E(t){const e=this.options.animationSelector;if(!1===e)return[Promise.resolve()];const n=a(e,document.body);return n.length?n.map(t=>function(t,e,n){void 0===n&&(n=null);const{type:i,timeout:s,propCount:o}=function(t,e){void 0===e&&(e=null);const n=window.getComputedStyle(t),i=`${m}Duration`,s=`${v}Delay`,o=`${v}Duration`,r=n[`${m}Delay`].split(", "),a=(n[i]||"").split(", "),l=P(r,a),c=(n[s]||"").split(", "),u=(n[o]||"").split(", "),h=P(c,u);let d="",p=0,g=0;return"transition"===e?l>0&&(d="transition",p=l,g=a.length):"animation"===e?h>0&&(d="animation",p=h,g=u.length):(p=Math.max(l,h),d=p>0?l>h?"transition":"animation":null,g=d?"transition"===d?a.length:u.length:0),{type:d,timeout:p,propCount:g}}(t,n);return i&&s?new Promise(e=>{const n="transition"===i?f:w,r=performance.now();let a=0;const l=()=>{t.removeEventListener(n,c),e()},c=e=>{if(e.target===t){if(!(t=>!!t.elapsedTime)(e))throw new Error("Not a transition or animation event.");(performance.now()-r)/1e3<e.elapsedTime||++a>=o&&l()}};setTimeout(()=>{a<o&&l()},s+1),t.addEventListener(n,c)}):(console.warn(`[swup] No CSS transition duration defined for element of selector ${e}`),Promise.resolve())}(t,e)):(console.warn(`[swup] No animated elements found by selector ${e}`),[Promise.resolve()])}function P(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max(...e.map((e,n)=>l(e)+l(t[n])))}void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(m="WebkitTransition",f="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(v="WebkitAnimation",w="webkitAnimationEnd");const S=function(t){const e=((t,e)=>{let n=document.createElement("html");n.innerHTML=t;let i=[];e.forEach(t=>{if(null==r(t,n))return console.warn(`[swup] Container ${t} not found on page.`),null;a(t).length!==a(t,n).length&&console.warn("[swup] Mismatched number of containers found on new page."),a(t).forEach((e,s)=>{a(t,n)[s].setAttribute("data-swup",String(i.length)),i.push(a(t,n)[s].outerHTML)})});const s=r("title",n)?.innerText||"",o=r("body",n)?.className;return n.innerHTML="",n=null,{title:s,pageClass:o,blocks:i,originalContent:t}})(t.responseText,this.options.containers);return e?{...e,responseURL:t.responseURL||window.location.href}:(console.warn("[swup] Received page is invalid."),null)};function y(t){const e=this.options.requestHeaders,{url:n}=t;return this.cache.exists(n)?(this.triggerEvent("pageRetrievedFromCache"),Promise.resolve(this.cache.getPage(n))):new Promise((i,s)=>{((t,e)=>{const n={url:window.location.pathname+window.location.search,method:"GET",data:null,headers:{}},{url:i,method:s,headers:o,data:r}={...n,...t},a=new XMLHttpRequest;a.onreadystatechange=function(){4===a.readyState&&e(a)},a.open(s,i,!0),Object.entries(o).forEach(t=>{let[e,n]=t;a.setRequestHeader(e,n)}),a.send(r)})({...t,headers:e},t=>{if(500===t.status)return this.triggerEvent("serverError"),void s(n);const e=this.getPageData(t);if(!e||!e.blocks.length)return void s(n);const o={...e,url:n};this.cache.cacheUrl(o),this.triggerEvent("pageLoaded"),i(o)})})}const b=function(t){let{event:e,skipTransition:n}=void 0===t?{}:t;const i=e instanceof PopStateEvent;if(n)return this.triggerEvent("animationSkipped"),[Promise.resolve()];this.triggerEvent("animationOutStart"),document.documentElement.classList.add("is-changing","is-leaving","is-animating"),i&&document.documentElement.classList.add("is-popstate");const s=this.getAnimationPromises("out");return Promise.all(s).then(()=>{this.triggerEvent("animationOutDone")}),s};function k(t){const{url:e}=t;this.shouldIgnoreVisit(e)?window.location.href=e:this.performPageLoad(t)}function U(e){const{url:n,event:i,customTransition:s}=e??{},o=i instanceof PopStateEvent,r=this.shouldSkipTransition({url:n,event:i});var a;this.triggerEvent("transitionStart",i),this.updateTransition(t(),n,s),null!=s&&document.documentElement.classList.add(`to-${a=s,String(a).toLowerCase().replace(/[\s/_.]+/g,"-").replace(/[^\w-]+/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"")||""}`);const l=this.leavePage({event:i,skipTransition:r}),c=this.fetchPage(e);o||function(e,n){void 0===n&&(n={});const i={url:e=e||t({hash:!0}),random:Math.random(),source:"swup",...n};history.pushState(i,"",e)}(n+(this.scrollToElement||"")),this.currentPageUrl=t(),Promise.all([c,...l]).then(t=>{let[e]=t;this.renderPage(e,{event:i,skipTransition:r})}).catch(t=>{void 0!==t&&(this.options.skipPopStateHandling=()=>(window.location=t,!0),history.go(-1))})}const L=function(t){let{blocks:e,title:n}=t;return e.forEach((t,e)=>{document.body.querySelector(`[data-swup="${e}"]`).outerHTML=t}),document.title=n,Promise.resolve()};function T(t,e){const n=this._handlers[t];n?n.push(e):console.warn(`Unsupported event ${t}.`)}function C(t,e){if(t&&e){const n=this._handlers[t];n.includes(e)?this._handlers[t]=n.filter(t=>t!==e):console.warn(`Handler for event '${t}' not found.`)}else t?this._handlers[t]=[]:Object.keys(this._handlers).forEach(t=>{this._handlers[t]=[]})}function H(t,e){this._handlers[t].forEach(t=>{try{t(e)}catch(t){console.error(t)}});const n=new CustomEvent(`swup:${t}`,{detail:t});document.dispatchEvent(n)}const R=function(t){if(t?.isSwupPlugin){if(t.swup=this,!t._checkRequirements||t._checkRequirements())return t._beforeMount&&t._beforeMount(),t.mount(),this.plugins.push(t),this.plugins}else console.error("Not a swup plugin instance",t)};function A(t){const e=this.findPlugin(t);if(e)return e.unmount(),e._afterUnmount&&e._afterUnmount(),this.plugins=this.plugins.filter(t=>t!==e),this.plugins;console.error("No such plugin",e)}function $(t){return this.plugins.find(e=>e===t||e.name===t)}const _=function(n,i){let{event:s,skipTransition:o}=void 0===i?{}:i;if(document.documentElement.classList.remove("is-leaving"),!this.isSameResolvedUrl(t(),n.url))return;const{url:r}=c.fromUrl(n.responseURL);this.isSameResolvedUrl(t(),r)||(this.cache.cacheUrl({...n,url:r}),this.currentPageUrl=t(),e(r)),o||document.documentElement.classList.add("is-rendering"),this.triggerEvent("willReplaceContent",s),this.replaceContent(n).then(()=>{this.triggerEvent("contentReplaced",s),this.triggerEvent("pageView",s),this.options.cache||this.cache.empty(),this.enterPage({event:s,skipTransition:o}),this.scrollToElement=null})};function x(t,e,n){this.transition={from:t,to:e,custom:n}}function M(t){let{event:e}=t;return!(!(e instanceof PopStateEvent)||this.options.animateHistoryBrowsing)}return class{constructor(e){void 0===e&&(e={}),this.version="3.0.4",this._handlers={animationInDone:[],animationInStart:[],animationOutDone:[],animationOutStart:[],animationSkipped:[],clickLink:[],contentReplaced:[],disabled:[],enabled:[],openPageInNewTab:[],pageLoaded:[],pageRetrievedFromCache:[],pageView:[],popState:[],samePage:[],samePageWithHash:[],serverError:[],transitionStart:[],transitionEnd:[],willReplaceContent:[]},this.scrollToElement=null,this.options=void 0,this.plugins=[],this.transition={},this.cache=void 0,this.currentPageUrl=t(),this.delegatedListeners={},this.boundPopStateHandler=void 0,this.loadPage=k,this.performPageLoad=U,this.leavePage=b,this.renderPage=_,this.replaceContent=L,this.enterPage=p,this.triggerEvent=H,this.delegateEvent=o,this.on=T,this.off=C,this.updateTransition=x,this.shouldSkipTransition=M,this.getAnimationPromises=E,this.getPageData=S,this.fetchPage=y,this.getAnchorElement=g,this.log=()=>{},this.use=R,this.unuse=A,this.findPlugin=$,this.getCurrentUrl=t,this.cleanupAnimationClasses=h,this.defaults={animateHistoryBrowsing:!1,animationSelector:'[class*="transition-"]',cache:!0,containers:["#swup"],ignoreVisit:function(t,e){let{el:n}=void 0===e?{}:e;return!!n?.closest("[data-no-swup]")},linkSelector:"a[href]",plugins:[],resolveUrl:t=>t,requestHeaders:{"X-Requested-With":"swup",Accept:"text/html, application/xhtml+xml"},skipPopStateHandling:t=>"swup"!==t.state?.source},this.options={...this.defaults,...e},this.boundPopStateHandler=this.popStateHandler.bind(this),this.cache=new d(this),this.enable()}enable(){"undefined"!=typeof Promise?(this.delegatedListeners.click=o(this.options.linkSelector,"click",this.linkClickHandler.bind(this)),window.addEventListener("popstate",this.boundPopStateHandler),((t,e)=>{let n=0;this.options.containers.forEach(e=>{null==r(e,t)?console.warn(`[swup] Container ${e} not found on page.`):a(e).forEach((i,s)=>{a(e,t)[s].setAttribute("data-swup",String(n)),n++})})})(document.documentElement),this.options.plugins.forEach(t=>this.use(t)),e(),this.triggerEvent("enabled"),document.documentElement.classList.add("swup-enabled"),this.triggerEvent("pageView")):console.warn("Promise is not supported")}destroy(){this.delegatedListeners.click.destroy(),window.removeEventListener("popstate",this.boundPopStateHandler),this.cache.empty(),this.options.plugins.forEach(t=>{this.unuse(t)}),a("[data-swup]").forEach(t=>{t.removeAttribute("data-swup")}),this.off(),this.triggerEvent("disabled"),document.documentElement.classList.remove("swup-enabled")}shouldIgnoreVisit(t,e){let{el:n}=void 0===e?{}:e;const{origin:i,url:s,hash:o}=c.fromUrl(t);return i!==window.location.origin||!(!n||!this.triggerWillOpenNewWindow(n))||!!this.options.ignoreVisit(s+o,{el:n})}linkClickHandler(e){const n=e.delegateTarget,{href:i,url:s,hash:o}=c.fromElement(n);if(this.shouldIgnoreVisit(i,{el:n}))return;if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return void this.triggerEvent("openPageInNewTab",e);if(0!==e.button)return;if(this.triggerEvent("clickLink",e),e.preventDefault(),!s||s===t())return void this.handleLinkToSamePage(s,o,e);if(this.isSameResolvedUrl(s,t()))return;this.scrollToElement=o||null;const r=n.getAttribute("data-swup-transition")||void 0;this.performPageLoad({url:s,customTransition:r})}handleLinkToSamePage(t,n,i){if(n){if(this.triggerEvent("samePageWithHash",i),!g(n))return console.warn(`Element for offset not found (#${n})`);e(t+n)}else this.triggerEvent("samePage",i)}triggerWillOpenNewWindow(t){return!!t.matches('[download], [target="_blank"]')}popStateHandler(e){if(this.options.skipPopStateHandling(e))return;if(this.isSameResolvedUrl(t(),this.currentPageUrl))return;const n=e.state?.url??location.href;if(this.shouldIgnoreVisit(n))return;const{url:i,hash:s}=c.fromUrl(n);s?this.scrollToElement=s:e.preventDefault(),this.triggerEvent("popState",e),this.options.animateHistoryBrowsing||(document.documentElement.classList.remove("is-animating"),h()),this.performPageLoad({url:i,event:e})}resolveUrl(t){if("function"!=typeof this.options.resolveUrl)return console.warn("[swup] options.resolveUrl expects a callback function."),t;const e=this.options.resolveUrl(t);return e&&"string"==typeof e?e.startsWith("//")||e.startsWith("http")?(console.warn("[swup] options.resolveUrl needs to return a relative url"),t):e:(console.warn("[swup] options.resolveUrl needs to return a url"),t)}isSameResolvedUrl(t,e){return this.resolveUrl(t)===this.resolveUrl(e)}}});
//# sourceMappingURL=Swup.umd.js.map

@@ -1,10 +0,10 @@

export { classify } from './helpers/classify.js';
export { createHistoryRecord } from './helpers/createHistoryRecord.js';
export { updateHistoryRecord } from './helpers/updateHistoryRecord.js';
export { delegateEvent } from './helpers/delegateEvent.js';
export { getDataFromHtml } from './helpers/getDataFromHtml.js';
export { fetch } from './helpers/fetch.js';
export { getCurrentUrl } from './helpers/getCurrentUrl.js';
export { Location } from './helpers/Location.js';
export { markSwupElements } from './helpers/markSwupElements.js';
export { cleanupAnimationClasses } from './helpers/cleanupAnimationClasses.js';
export { classify } from './helpers/classify';
export { createHistoryRecord } from './helpers/createHistoryRecord';
export { updateHistoryRecord } from './helpers/updateHistoryRecord';
export { delegateEvent } from './helpers/delegateEvent';
export { getDataFromHtml } from './helpers/getDataFromHtml';
export { fetch } from './helpers/fetch';
export { getCurrentUrl } from './helpers/getCurrentUrl';
export { Location } from './helpers/Location';
export { markSwupElements } from './helpers/markSwupElements';
export { cleanupAnimationClasses } from './helpers/cleanupAnimationClasses';

@@ -1,5 +0,7 @@

import { DelegateEventHandler, DelegateOptions } from 'delegate-it';
import delegate from 'delegate-it';
export type Unsubscribe = {
destroy: () => void;
};
export declare const delegateEvent: <Selector extends string, TEvent extends keyof GlobalEventHandlersEventMap>(selector: Selector, type: TEvent, callback: DelegateEventHandler<GlobalEventHandlersEventMap[TEvent], Element>, options?: DelegateOptions) => Unsubscribe;
export declare const delegateEvent: <Selector extends string, TEvent extends keyof GlobalEventHandlersEventMap>(selector: Selector, type: TEvent, callback: delegate.EventHandler<GlobalEventHandlersEventMap[TEvent], Element>, { base, ...eventOptions }?: {
base?: Document | undefined;
}) => Unsubscribe;

@@ -1,5 +0,5 @@

import { TransitionOptions } from '../modules/loadPage.js';
import { Options } from '../Swup.js';
import { TransitionOptions } from '../modules/loadPage';
import { Options } from '../Swup';
export declare const fetch: (options: TransitionOptions & {
headers: Options['requestHeaders'];
}, callback: (request: XMLHttpRequest) => void) => XMLHttpRequest;

@@ -1,7 +0,7 @@

import Swup, { Options } from './Swup.js';
import { Plugin } from './modules/plugins.js';
import { Handler } from './modules/events.js';
import Swup, { Options } from './Swup';
import { Plugin } from './modules/plugins';
import { Handler } from './modules/events';
export default Swup;
export * from './helpers.js';
export * from './utils.js';
export * from './helpers';
export * from './utils';
export type { Options, Plugin, Handler };

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { PageData } from './getPageData.js';
import Swup from '../Swup';
import { PageData } from './getPageData';
export interface PageRecord extends PageData {

@@ -4,0 +4,0 @@ url: string;

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { PageRenderOptions } from './renderPage.js';
import Swup from '../Swup';
import { PageRenderOptions } from './renderPage';
export declare const enterPage: (this: Swup, { event, skipTransition }?: PageRenderOptions) => Promise<void>[];

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { DelegateEvent } from 'delegate-it';
import Swup from '../Swup';
import delegate from 'delegate-it';
type HandlersEventMap = {

@@ -9,7 +9,7 @@ animationInDone: undefined;

animationSkipped: undefined;
clickLink: DelegateEvent<MouseEvent>;
clickLink: delegate.Event<MouseEvent>;
contentReplaced: PopStateEvent | undefined;
disabled: undefined;
enabled: undefined;
openPageInNewTab: DelegateEvent<MouseEvent>;
openPageInNewTab: delegate.Event<MouseEvent>;
pageLoaded: undefined;

@@ -19,4 +19,4 @@ pageRetrievedFromCache: undefined;

popState: PopStateEvent;
samePage: DelegateEvent<MouseEvent>;
samePageWithHash: DelegateEvent<MouseEvent>;
samePage: delegate.Event<MouseEvent>;
samePageWithHash: delegate.Event<MouseEvent>;
serverError: undefined;

@@ -23,0 +23,0 @@ transitionStart: PopStateEvent | undefined;

@@ -1,4 +0,4 @@

import Swup from '../Swup.js';
import { TransitionOptions } from './loadPage.js';
import { PageRecord } from './Cache.js';
import Swup from '../Swup';
import { TransitionOptions } from './loadPage';
import { PageRecord } from './Cache';
export declare function fetchPage(this: Swup, data: TransitionOptions): Promise<PageRecord>;

@@ -1,8 +0,1 @@

/**
* Find the anchor element for a given hash.
* @see https://html.spec.whatwg.org/#find-a-potential-indicated-element
*
* @param hash Hash with or without leading '#'
* @returns The element, if found, or null.
*/
export declare const getAnchorElement: (hash: string) => Element | null;

@@ -1,2 +0,2 @@

import Swup from '../Swup.js';
import Swup from '../Swup';
export declare function getAnimationPromises(this: Swup, animationType: 'in' | 'out'): Promise<void>[];

@@ -3,0 +3,0 @@ export declare function getTransitionInfo(element: Element, expectedType?: 'animation' | 'transition' | null): {

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { PageHtmlData } from '../helpers/getDataFromHtml.js';
import Swup from '../Swup';
import { PageHtmlData } from '../helpers/getDataFromHtml';
export type PageData = PageHtmlData & {

@@ -4,0 +4,0 @@ responseURL: string;

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { PageRenderOptions } from './renderPage.js';
import Swup from '../Swup';
import { PageRenderOptions } from './renderPage';
export declare const leavePage: (this: Swup, { event, skipTransition }?: PageRenderOptions) => Promise<void>[];

@@ -1,15 +0,12 @@

import Swup from '../Swup.js';
export type HistoryAction = 'push' | 'replace';
import Swup from '../Swup';
export type TransitionOptions = {
url: string;
customTransition?: string;
history?: HistoryAction;
};
export type PageLoadOptions = {
url: string;
event?: PopStateEvent;
customTransition?: string;
history?: HistoryAction;
event?: PopStateEvent;
};
export declare function loadPage(this: Swup, data: TransitionOptions): void;
export declare function performPageLoad(this: Swup, data: PageLoadOptions): void;

@@ -1,2 +0,2 @@

import Swup from '../Swup.js';
import Swup from '../Swup';
export type Plugin = {

@@ -3,0 +3,0 @@ name: string;

@@ -1,3 +0,3 @@

import Swup from '../Swup.js';
import { PageRecord } from './Cache.js';
import Swup from '../Swup';
import { PageRecord } from './Cache';
export type PageRenderOptions = {

@@ -4,0 +4,0 @@ event?: PopStateEvent;

@@ -1,2 +0,2 @@

import Swup from '../Swup.js';
import Swup from '../Swup';
export declare function updateTransition(this: Swup, from: string, to: string, custom?: string): void;

@@ -3,0 +3,0 @@ export declare function shouldSkipTransition(this: Swup, { event }: {

@@ -1,10 +0,10 @@

import { DelegateEvent } from 'delegate-it';
import { Unsubscribe } from './helpers/delegateEvent.js';
import { Cache } from './modules/Cache.js';
import { getAnimationPromises } from './modules/getAnimationPromises.js';
import { fetchPage } from './modules/fetchPage.js';
import { loadPage, performPageLoad } from './modules/loadPage.js';
import { on, off, triggerEvent, Handlers } from './modules/events.js';
import { unuse, findPlugin, Plugin } from './modules/plugins.js';
import { updateTransition, shouldSkipTransition } from './modules/transitions.js';
import delegate from 'delegate-it';
import { Unsubscribe } from './helpers/delegateEvent';
import { Cache } from './modules/Cache';
import { getAnimationPromises } from './modules/getAnimationPromises';
import { fetchPage } from './modules/fetchPage';
import { loadPage, performPageLoad } from './modules/loadPage';
import { on, off, triggerEvent, Handlers } from './modules/events';
import { unuse, findPlugin, Plugin } from './modules/plugins';
import { updateTransition, shouldSkipTransition } from './modules/transitions';
export type Transition = {

@@ -27,5 +27,4 @@ from?: string;

skipPopStateHandling: (event: any) => boolean;
ignoreVisit: (url: string, { el, event }: {
ignoreVisit: (url: string, { el }: {
el?: Element;
event?: Event;
}) => boolean;

@@ -47,4 +46,4 @@ resolveUrl: (url: string) => string;

performPageLoad: typeof performPageLoad;
leavePage: (this: Swup, { event, skipTransition }?: import("./modules/renderPage.js").PageRenderOptions) => Promise<void>[];
renderPage: (this: Swup, page: import("./modules/Cache.js").PageRecord, { event, skipTransition }?: import("./modules/renderPage.js").PageRenderOptions) => void;
leavePage: (this: Swup, { event, skipTransition }?: import("./modules/renderPage").PageRenderOptions) => Promise<void>[];
renderPage: (this: Swup, page: import("./modules/Cache").PageRecord, { event, skipTransition }?: import("./modules/renderPage").PageRenderOptions) => void;
replaceContent: ({ blocks, title }: {

@@ -54,5 +53,7 @@ blocks: string[];

}) => Promise<void>;
enterPage: (this: Swup, { event, skipTransition }?: import("./modules/renderPage.js").PageRenderOptions) => Promise<void>[];
enterPage: (this: Swup, { event, skipTransition }?: import("./modules/renderPage").PageRenderOptions) => Promise<void>[];
triggerEvent: typeof triggerEvent;
delegateEvent: <Selector extends string, TEvent extends keyof GlobalEventHandlersEventMap>(selector: Selector, type: TEvent, callback: import("delegate-it").DelegateEventHandler<GlobalEventHandlersEventMap[TEvent], Element>, options?: import("delegate-it").DelegateOptions | undefined) => Unsubscribe;
delegateEvent: <Selector extends string, TEvent extends keyof GlobalEventHandlersEventMap>(selector: Selector, type: TEvent, callback: delegate.EventHandler<GlobalEventHandlersEventMap[TEvent], Element>, { base, ...eventOptions }?: {
base?: Document | undefined;
}) => Unsubscribe;
on: typeof on;

@@ -63,3 +64,3 @@ off: typeof off;

getAnimationPromises: typeof getAnimationPromises;
getPageData: (this: Swup, request: XMLHttpRequest) => import("./modules/getPageData.js").PageData | null;
getPageData: (this: Swup, request: XMLHttpRequest) => import("./modules/getPageData").PageData | null;
fetchPage: typeof fetchPage;

@@ -79,8 +80,7 @@ getAnchorElement: (hash: string) => Element | null;

destroy(): void;
shouldIgnoreVisit(href: string, { el, event }?: {
shouldIgnoreVisit(href: string, { el }?: {
el?: Element;
event?: Event;
}): boolean;
linkClickHandler(event: DelegateEvent<MouseEvent>): void;
handleLinkToSamePage(url: string, hash: string, event: DelegateEvent<MouseEvent>): void;
linkClickHandler(event: delegate.Event<MouseEvent>): void;
handleLinkToSamePage(url: string, hash: string, event: delegate.Event<MouseEvent>): void;
triggerWillOpenNewWindow(triggerEl: Element): boolean;

@@ -87,0 +87,0 @@ popStateHandler(event: PopStateEvent): void;

@@ -1,1 +0,1 @@

export * from './utils/index.js';
export * from './utils/index';
{
"name": "swup",
"amdName": "Swup",
"version": "3.1.1",
"description": "Complete, flexible, extensible, and easy-to-use page transition library for your server-side rendered website.",
"version": "4.0.0-rc.14",
"description": "Versatile and extensible page transition library for server-side rendered websites",
"type": "module",

@@ -37,2 +37,3 @@ "source": "./src/Swup.ts",

"test:unit": "vitest run --config ./vitest/vitest.config.ts",
"test:unit:watch": "vitest --config ./vitest/vitest.config.ts",
"test:e2e": "start-server-and-test test:e2e:start 8274 cy:run",

@@ -63,3 +64,4 @@ "test:e2e:ci": "start-server-and-test test:e2e:start 8274 cy:run:record",

"delegate-it": "^6.0.0",
"opencollective-postinstall": "^2.0.2"
"opencollective-postinstall": "^2.0.2",
"path-to-regexp": "^6.2.1"
},

@@ -75,7 +77,8 @@ "devDependencies": {

"istanbul-lib-coverage": "^3.2.0",
"jsdom": "^22.1.0",
"microbundle": "^0.15.0",
"nyc": "^15.1.0",
"prettier": "^2.8.2",
"start-server-and-test": "^1.14.0",
"vitest": "^0.29.8"
"start-server-and-test": "^2.0.0",
"vitest": "^0.31.2"
},

@@ -82,0 +85,0 @@ "collective": {

@@ -19,3 +19,3 @@ <br>

Complete, flexible, extensible, and easy-to-use page transition library for your server-side rendered website.
Versatile and extensible page transition library for server-side rendered websites

@@ -30,18 +30,36 @@ [Features](#features) •

Swup is a library that helps you add page transitions to server-side rendered websites. It handles
the complete lifecycle of a page visit by intercepting link clicks, loading the new page in the
background, replacing the content and transitioning between the old and the new page.
Swup adds page transitions to server-side rendered websites. It manages the complete lifecycle of a
page visit by intercepting link clicks, loading the new page in the background and smoothly
transitioning between the old and new content.
Its goal is to make adding transitions to a site as simple as possible, while providing lots of
other quality-of-life improvements.
Its goal is to make it effortless to add page transitions to a site, while providing lots of other
quality-of-life improvements.
## Features
- ✨ Auto-detects [CSS transitions](https://swup.js.org/getting-started/how-it-works) for perfect timing
- 🔗 Updates URLs and preserves native browser history behavior
- 📦 Uses a [cache](https://swup.js.org/api/cache) to speed up subsequent page loads
- 💡 Offers [events](https://swup.js.org/events) for hooking into the lifecycle
- 🔌 Has a powerful [plugin system](https://swup.js.org/plugins) and many official and third-party plugins
- 🎨 Provides ready-to-go [themes](https://swup.js.org/themes) to get started quickly
- ✏️ Works out of the box with [minimal markup](https://swup.js.org/getting-started/example/)
- ✨ Auto-detects [CSS transitions](https://swup.js.org/getting-started/how-it-works/) for perfect timing
- 🔗 Updates URLs and preserves native [browser history](https://swup.js.org/options/#animatehistorybrowsing)
- 🏓 Manages scroll position between pages and anchor jump links
- 🚀 Uses a [cache](https://swup.js.org/api/cache/) to speed up subsequent page loads
- 📡 Offers [hooks](https://swup.js.org/hooks/) to customize and extend the page load lifecycle
- 🔌 Has a powerful [plugin system](https://swup.js.org/plugins/) and many official and third-party plugins
- 🎨 Provides ready-to-go [themes](https://swup.js.org/themes/) to get started quickly
## Plugins
Swup is small by design. Extended features can be added via [plugins](https://swup.js.org/plugins/):
- Display a [progress bar](https://swup.js.org/plugins/progress-plugin/) while loading
- Enable [smooth scrolling](https://swup.js.org/plugins/scroll-plugin/) between visits
- Update [meta tags and stylesheets](https://swup.js.org/plugins/head-plugin/) after page loads
- Add support for [preloading pages](https://swup.js.org/plugins/preload-plugin/) in the background
- Improve [accessibility](https://swup.js.org/plugins/a11y-plugin/) for screen readers
- Perform your [animations in JS](https://swup.js.org/plugins/js-plugin/) instead of CSS transitions
- Animate [form submissions](https://swup.js.org/plugins/forms-plugin/)
- Get help in [debug mode](https://swup.js.org/plugins/debug-plugin/)
Check out the list of [all official plugins](https://swup.js.org/plugins/) as well as
[third-party integrations](https://swup.js.org/third-party-integrations/).
## Examples

@@ -48,0 +66,0 @@

@@ -6,2 +6,3 @@ import { DelegateEvent } from 'delegate-it';

import Swup, { Options, Plugin } from '../index.js';
import * as SwupTS from '../Swup.js';

@@ -55,2 +56,6 @@ const baseUrl = window.location.origin;

});
it('UMD compatibility: Swup.ts should only have a default export', () => {
expect(Object.keys(SwupTS)).toEqual(['default']);
});
});

@@ -87,3 +92,3 @@

const swup = new Swup({ ignoreVisit });
swup.loadPage({ url: '/path/' });
swup.loadPage('/path/');

@@ -90,0 +95,0 @@ expect(ignoreVisit.mock.calls).toHaveLength(1);

// Re-export all helpers to allow custom package export path
// e.g. import { getPageData } from 'swup/helpers'
// e.g. import { updateHistoryRecord } from 'swup'

@@ -8,7 +8,5 @@ export { classify } from './helpers/classify.js';

export { delegateEvent } from './helpers/delegateEvent.js';
export { getDataFromHtml } from './helpers/getDataFromHtml.js';
export { fetch } from './helpers/fetch.js';
export { getCurrentUrl } from './helpers/getCurrentUrl.js';
export { Location } from './helpers/Location.js';
export { markSwupElements } from './helpers/markSwupElements.js';
export { cleanupAnimationClasses } from './helpers/cleanupAnimationClasses.js';
export { matchPath } from './helpers/matchPath.js';

@@ -15,2 +15,3 @@ import delegate, { DelegateEventHandler, DelegateOptions, EventType } from 'delegate-it';

const controller = new AbortController();
options = { ...options, signal: controller.signal };
delegate<string, ParseSelector<Selector, HTMLElement>, TEvent>(

@@ -17,0 +18,0 @@ selector,

@@ -8,7 +8,10 @@ /**

export class Location extends URL {
constructor(url: string, base: string = document.baseURI) {
constructor(url: URL | string, base: string = document.baseURI) {
super(url.toString(), base);
}
get url() {
/**
* The full local path including query params.
*/
get url(): string {
return this.pathname + this.search;

@@ -19,7 +22,7 @@ }

* Instantiate a Location from an element's href attribute
* @param {Element} el
* @param el
* @return new Location instance
*/
static fromElement(el: HTMLAnchorElement): Location {
const href = el.getAttribute('href') || el.getAttribute('xlink:href');
static fromElement(el: Element): Location {
const href = el.getAttribute('href') || el.getAttribute('xlink:href') || '';
return new Location(href!);

@@ -30,8 +33,8 @@ }

* Instantiate a Location from a URL object or string
* @param {URL|string} url
* @param url
* @return new Location instance
*/
static fromUrl(url: string): Location {
static fromUrl(url: URL | string): Location {
return new Location(url);
}
}

@@ -1,4 +0,7 @@

import Swup, { Options } from './Swup.js';
import { Plugin } from './modules/plugins.js';
import { Handler } from './modules/events.js';
import Swup, { type Options } from './Swup.js';
import type { CacheData } from './modules/Cache.js';
import type { Context, PageContext } from './modules/Context.js';
import type { Plugin } from './modules/plugins.js';
import type { HookDefinitions, Handler } from './modules/Hooks.js';
import type { Path } from 'path-to-regexp';

@@ -10,2 +13,2 @@ export default Swup;

export type { Options, Plugin, Handler };
export type { Options, Plugin, CacheData, Context, PageContext, HookDefinitions, Handler, Path };

@@ -1,13 +0,10 @@

import { getCurrentUrl, Location } from '../helpers.js';
import Swup from '../Swup.js';
import { PageData } from './getPageData.js';
import { Location } from '../helpers.js';
import { PageData } from './fetchPage.js';
export interface PageRecord extends PageData {
url: string;
responseURL: string;
}
export interface CacheData extends PageData {}
export class Cache {
pages: Record<string, PageRecord> = {};
last: PageRecord | null = null;
swup: Swup;
private swup: Swup;
private pages: Map<string, CacheData> = new Map();

@@ -18,39 +15,52 @@ constructor(swup: Swup) {

getCacheUrl(url: string): string {
return this.swup.resolveUrl(Location.fromUrl(url).url);
get size() {
return this.pages.size;
}
cacheUrl(page: PageRecord) {
page.url = this.getCacheUrl(page.url);
if (page.url in this.pages === false) {
this.pages[page.url] = page;
}
page.responseURL = this.getCacheUrl(page.responseURL);
this.last = this.pages[page.url];
this.swup.log(`Cache (${Object.keys(this.pages).length})`, this.pages);
get all() {
return this.pages;
}
getPage(url: string): PageRecord {
url = this.getCacheUrl(url);
return this.pages[url];
public has(url: string): boolean {
return this.pages.has(this.resolve(url));
}
getCurrentPage(): PageRecord {
return this.getPage(getCurrentUrl());
public get(url: string): CacheData | undefined {
return this.pages.get(this.resolve(url));
}
exists(url: string): boolean {
url = this.getCacheUrl(url);
return url in this.pages;
public set(url: string, page: CacheData) {
url = this.resolve(url);
page = { ...page, url };
this.pages.set(url, page);
this.swup.hooks.triggerSync('pageCached', { page });
}
empty(): void {
this.pages = {};
this.last = null;
this.swup.log('Cache cleared');
public update(url: string, page: CacheData) {
url = this.resolve(url);
page = { ...this.get(url), ...page, url };
this.pages.set(url, page);
}
remove(url: string): void {
delete this.pages[this.getCacheUrl(url)];
public delete(url: string): void {
this.pages.delete(this.resolve(url));
}
public clear(): void {
this.pages.clear();
this.swup.hooks.triggerSync('cacheCleared');
}
public prune(predicate: (url: string, page: CacheData) => boolean): void {
this.pages.forEach((page, url) => {
if (predicate(url, page)) {
this.delete(url);
}
});
}
private resolve(urlToResolve: string): string {
const { url } = Location.fromUrl(urlToResolve);
return this.swup.resolveUrl(url);
}
}

@@ -0,24 +1,26 @@

import Swup from '../Swup.js';
import { nextTick } from '../utils.js';
import Swup from '../Swup.js';
import { PageRenderOptions } from './renderPage.js';
export const enterPage = function (this: Swup, { event, skipTransition }: PageRenderOptions = {}) {
if (skipTransition) {
this.triggerEvent('transitionEnd', event);
this.cleanupAnimationClasses();
return [Promise.resolve()];
export const enterPage = async function (this: Swup) {
if (this.context.transition.animate) {
const animation = this.hooks.trigger(
'awaitAnimation',
{ selector: this.options.animationSelector, direction: 'in' },
async (context, { selector, direction }) => {
await Promise.all(this.getAnimationPromises({ selector, direction }));
}
);
await nextTick();
await this.hooks.trigger('animationInStart', undefined, () => {
document.documentElement.classList.remove('is-animating');
});
await animation;
await this.hooks.trigger('animationInDone');
}
nextTick(() => {
this.triggerEvent('animationInStart');
document.documentElement.classList.remove('is-animating');
await this.hooks.trigger('transitionEnd', undefined, () => {
this.cleanupAnimationClasses();
});
const animationPromises = this.getAnimationPromises('in');
Promise.all(animationPromises).then(() => {
this.triggerEvent('animationInDone');
this.triggerEvent('transitionEnd', event);
this.cleanupAnimationClasses();
});
return animationPromises;
this.context = this.createContext({ to: undefined });
};
import Swup from '../Swup.js';
import { fetch } from '../helpers.js';
import { TransitionOptions } from './loadPage.js';
import { PageRecord } from './Cache.js';
import { Location } from '../helpers.js';
export function fetchPage(this: Swup, data: TransitionOptions): Promise<PageRecord> {
const headers = this.options.requestHeaders;
const { url } = data;
export interface PageData {
url: string;
html: string;
}
if (this.cache.exists(url)) {
this.triggerEvent('pageRetrievedFromCache');
return Promise.resolve(this.cache.getPage(url));
export interface FetchOptions extends RequestInit {
method?: 'GET' | 'POST';
body?: string | FormData | URLSearchParams;
headers?: Record<string, string>;
}
export class FetchError extends Error {
url: string;
status: number;
constructor(message: string, details: { url: string; status: number }) {
super(message);
this.name = 'FetchError';
this.url = details.url;
this.status = details.status;
}
}
return new Promise((resolve, reject) => {
fetch({ ...data, headers }, (response) => {
if (response.status === 500) {
this.triggerEvent('serverError');
reject(url);
return;
}
// get json data
const page = this.getPageData(response);
if (!page || !page.blocks.length) {
reject(url);
return;
}
// render page
const cacheablePageData = { ...page, url };
this.cache.cacheUrl(cacheablePageData);
this.triggerEvent('pageLoaded');
resolve(cacheablePageData);
});
});
/**
* Fetch a page from the server, return it and cache it.
*/
export async function fetchPage(
this: Swup,
url: URL | string,
options: FetchOptions & { triggerHooks?: boolean } = {}
): Promise<PageData> {
const { url: requestUrl } = Location.fromUrl(url);
if (this.cache.has(requestUrl)) {
const page = this.cache.get(requestUrl) as PageData;
if (options.triggerHooks !== false) {
await this.hooks.trigger('pageLoaded', { page, cache: true });
}
return page;
}
const headers = { ...this.options.requestHeaders, ...options.headers };
options = { ...options, headers };
// Allow hooking before this and returning a custom response-like object (e.g. custom fetch implementation)
const response = await this.hooks.trigger(
'fetchPage',
{ url: requestUrl, options },
async (context, { url, options, response }) => await (response || fetch(url, options))
);
const { status, url: responseUrl } = response;
const html = await response.text();
if (status === 500) {
this.hooks.trigger('serverError', { status, response, url: responseUrl });
throw new FetchError(`Server error: ${responseUrl}`, { status, url: responseUrl });
}
if (!html) {
throw new FetchError(`Empty response: ${responseUrl}`, { status, url: responseUrl });
}
// Resolve real url after potential redirect
const { url: finalUrl } = new Location(responseUrl);
const page = { url: finalUrl, html };
// Only save cache entry for non-redirects
if (requestUrl === finalUrl) {
this.cache.set(page.url, page);
}
if (options.triggerHooks !== false) {
await this.hooks.trigger('pageLoaded', { page, cache: false });
}
return page;
}
import { queryAll, toMs } from '../utils.js';
import Swup from '../Swup.js';
import Swup, { Options } from '../Swup.js';
// Transition property/event sniffing
let transitionProp = 'transition';
let transitionEndEvent = 'transitionend';
let animationProp = 'animation';
let animationEndEvent = 'animationend';
const TRANSITION = 'transition';
const ANIMATION = 'animation';
if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
transitionProp = 'WebkitTransition';
transitionEndEvent = 'webkitTransitionEnd';
}
type AnimationTypes = typeof TRANSITION | typeof ANIMATION;
type AnimationProperties = 'Delay' | 'Duration';
type AnimationStyleKeys = `${AnimationTypes}${AnimationProperties}` | 'transitionProperty';
type AnimationStyleDeclarations = Pick<CSSStyleDeclaration, AnimationStyleKeys>;
if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
animationProp = 'WebkitAnimation';
animationEndEvent = 'webkitAnimationEnd';
}
export type AnimationDirection = 'in' | 'out';
/**
* Get an array of Promises that resolve when all animations are done on the page.
* @note We don't make use of the `direction` argument, but it's required by JS plugin
*/
export function getAnimationPromises(
this: Swup,
// we don't use this argument, but JS plugin depends on it with
// its own version of getAnimationPromises, so it must be specified when
// getAnimationPromises is being used
animationType: 'in' | 'out'
{
elements,
selector
}: {
selector: Options['animationSelector'];
elements?: NodeListOf<HTMLElement> | HTMLElement[];
direction?: AnimationDirection;
}
): Promise<void>[] {
const selector = this.options.animationSelector;
// Use array of a single resolved promise instead of an empty array to allow
// possible future use with Promise.race() which requires an actual value
const resolved = [Promise.resolve()];
// Allow usage of swup without animations
if (selector === false) {
// Use array of a single resolved promise instead of an empty array to allow
// possible future use with Promise.race() which requires an actual value
return [Promise.resolve()];
if (selector === false && !elements) {
return resolved;
}
const animatedElements = queryAll(selector, document.body);
// Warn if no elements match the animationSelector, but keep things going
if (!animatedElements.length) {
console.warn(`[swup] No elements found matching animationSelector \`${selector}\``);
return [Promise.resolve()];
// Allow passing in elements
let animatedElements: HTMLElement[] = [];
if (elements) {
animatedElements = Array.from(elements);
} else if (selector) {
animatedElements = queryAll(selector, document.body);
// Warn if no elements match the selector, but keep things going
if (!animatedElements.length) {
console.warn(`[swup] No elements found matching animationSelector \`${selector}\``);
return resolved;
}
}

@@ -49,6 +56,8 @@

if (!animationPromises.length) {
console.warn(
`[swup] No CSS animation duration defined on elements matching \`${selector}\``
);
return [Promise.resolve()];
if (selector) {
console.warn(
`[swup] No CSS animation duration defined on elements matching \`${selector}\``
);
}
return resolved;
}

@@ -59,5 +68,2 @@

const isTransitionOrAnimationEvent = (event: any): event is TransitionEvent | AnimationEvent =>
[transitionEndEvent, animationEndEvent].includes(event.type);
function getAnimationPromiseForElement(element: Element): Promise<void> | undefined {

@@ -72,3 +78,3 @@ const { type, timeout, propCount } = getTransitionInfo(element);

return new Promise((resolve) => {
const endEvent = type === 'transition' ? transitionEndEvent : animationEndEvent;
const endEvent = `${type}end`;
const startTime = performance.now();

@@ -114,43 +120,25 @@ let propsTransitioned = 0;

export function getTransitionInfo(
element: Element,
expectedType: 'animation' | 'transition' | null = null
) {
const styles = window.getComputedStyle(element);
export function getTransitionInfo(element: Element, expectedType?: AnimationTypes) {
const styles = window.getComputedStyle(element) as AnimationStyleDeclarations;
// not sure what to do about the below mess other than casting, but it's a mess
const transitionDelay = `${transitionProp}Delay` as keyof CSSStyleDeclaration;
const transitionDuration = `${transitionProp}Duration` as keyof CSSStyleDeclaration;
const animationDelay = `${animationProp}Delay` as keyof CSSStyleDeclaration;
const animationDuration = `${animationProp}Duration` as keyof CSSStyleDeclaration;
const transitionDelays = (
styles[transitionDelay] as CSSStyleDeclaration['transitionDelay']
).split(', ');
const transitionDurations = (
(styles[transitionDuration] || '') as CSSStyleDeclaration['transitionDuration']
).split(', ');
const transitionDelays = getStyleProperties(styles, `${TRANSITION}Delay`);
const transitionDurations = getStyleProperties(styles, `${TRANSITION}Duration`);
const transitionTimeout = calculateTimeout(transitionDelays, transitionDurations);
const animationDelays = (
(styles[animationDelay] || '') as CSSStyleDeclaration['animationDelay']
).split(', ');
const animationDurations = (
(styles[animationDuration] || '') as CSSStyleDeclaration['animationDuration']
).split(', ');
const animationDelays = getStyleProperties(styles, `${ANIMATION}Delay`);
const animationDurations = getStyleProperties(styles, `${ANIMATION}Duration`);
const animationTimeout = calculateTimeout(animationDelays, animationDurations);
let type: string | null = '';
let type: AnimationTypes | null = null;
let timeout = 0;
let propCount = 0;
if (expectedType === 'transition') {
if (expectedType === TRANSITION) {
if (transitionTimeout > 0) {
type = 'transition';
type = TRANSITION;
timeout = transitionTimeout;
propCount = transitionDurations.length;
}
} else if (expectedType === 'animation') {
} else if (expectedType === ANIMATION) {
if (animationTimeout > 0) {
type = 'animation';
type = ANIMATION;
timeout = animationTimeout;

@@ -161,10 +149,5 @@ propCount = animationDurations.length;

timeout = Math.max(transitionTimeout, animationTimeout);
type =
timeout > 0
? transitionTimeout > animationTimeout
? 'transition'
: 'animation'
: null;
type = timeout > 0 ? (transitionTimeout > animationTimeout ? TRANSITION : ANIMATION) : null;
propCount = type
? type === 'transition'
? type === TRANSITION
? transitionDurations.length

@@ -182,3 +165,11 @@ : animationDurations.length

function calculateTimeout(delays: string[], durations: string[]) {
function isTransitionOrAnimationEvent(event: any): event is TransitionEvent | AnimationEvent {
return [`${TRANSITION}end`, `${ANIMATION}end`].includes(event.type);
}
function getStyleProperties(styles: AnimationStyleDeclarations, key: AnimationStyleKeys): string[] {
return (styles[key] || '').split(', ');
}
function calculateTimeout(delays: string[], durations: string[]): number {
while (delays.length < durations.length) {

@@ -185,0 +176,0 @@ delays = delays.concat(delays);

import Swup from '../Swup.js';
import { PageRenderOptions } from './renderPage.js';
import { classify } from '../helpers.js';
export const leavePage = function (this: Swup, { event, skipTransition }: PageRenderOptions = {}) {
const isHistoryVisit = event instanceof PopStateEvent;
if (skipTransition) {
this.triggerEvent('animationSkipped');
return [Promise.resolve()];
export const leavePage = async function (this: Swup) {
if (!this.context.transition.animate) {
await this.hooks.trigger('animationSkipped');
return;
}
this.triggerEvent('animationOutStart');
await this.hooks.trigger('animationOutStart', undefined, () => {
document.documentElement.classList.add('is-changing', 'is-leaving', 'is-animating');
if (this.context.history.popstate) {
document.documentElement.classList.add('is-popstate');
}
if (this.context.transition.name) {
document.documentElement.classList.add(`to-${classify(this.context.transition.name)}`);
}
});
// handle classes
document.documentElement.classList.add('is-changing', 'is-leaving', 'is-animating');
if (isHistoryVisit) {
document.documentElement.classList.add('is-popstate');
}
await this.hooks.trigger(
'awaitAnimation',
{ selector: this.options.animationSelector, direction: 'out' },
async (context, { selector, direction }) => {
await Promise.all(this.getAnimationPromises({ selector, direction }));
}
);
// animation promise stuff
const animationPromises: Promise<void>[] = this.getAnimationPromises('out');
Promise.all(animationPromises).then(() => {
this.triggerEvent('animationOutDone');
});
return animationPromises;
await this.hooks.trigger('animationOutDone');
};

@@ -1,23 +0,20 @@

import { classify, createHistoryRecord, updateHistoryRecord, getCurrentUrl } from '../helpers.js';
import Swup from '../Swup.js';
import { PageRecord } from './Cache.js';
import { createHistoryRecord, updateHistoryRecord, getCurrentUrl, Location } from '../helpers.js';
import { FetchOptions } from '../modules/fetchPage.js';
import { ContextInitOptions } from './Context.js';
export type HistoryAction = 'push' | 'replace';
export type TransitionOptions = {
url: string;
customTransition?: string;
history?: HistoryAction;
};
export type PageLoadOptions = {
url: string;
customTransition?: string;
animate?: boolean;
transition?: string;
history?: HistoryAction;
event?: PopStateEvent;
};
export function loadPage(this: Swup, data: TransitionOptions) {
const { url } = data;
export function loadPage(
this: Swup,
url: string,
options: PageLoadOptions & FetchOptions = {},
context: Omit<ContextInitOptions, 'to'> = {}
) {
// Check if the visit should be ignored

@@ -27,56 +24,77 @@ if (this.shouldIgnoreVisit(url)) {

} else {
this.performPageLoad(data);
const { url: to, hash } = Location.fromUrl(url);
this.context = this.createContext({ ...context, to, hash });
this.performPageLoad(to, options);
}
}
export function performPageLoad(this: Swup, data: PageLoadOptions) {
const { url, event, customTransition, history: historyAction = 'push' } = data ?? {};
export async function performPageLoad(
this: Swup,
url: string,
options: PageLoadOptions & FetchOptions = {}
) {
if (typeof url !== 'string') {
throw new Error(`loadPage requires a URL parameter`);
}
const isHistoryVisit = event instanceof PopStateEvent;
const skipTransition = this.shouldSkipTransition({ url, event });
const { url: requestedUrl } = Location.fromUrl(url);
const { transition, animate, history: historyAction } = options;
options.referrer = options.referrer || this.currentPageUrl;
this.triggerEvent('transitionStart', event);
if (animate === false) {
this.context.transition.animate = false;
}
if (historyAction) {
this.context.history.action = historyAction;
}
// set transition object
this.updateTransition(getCurrentUrl(), url, customTransition);
if (customTransition != null) {
document.documentElement.classList.add(`to-${classify(customTransition)}`);
if (!this.context.transition.animate) {
document.documentElement.classList.remove('is-animating');
this.cleanupAnimationClasses();
} else if (transition) {
this.context.transition.name = transition;
}
// start/skip animation
const animationPromises = this.leavePage({ event, skipTransition });
try {
await this.hooks.trigger('transitionStart');
const animationPromise = this.leavePage();
const pagePromise = this.hooks.trigger(
'loadPage',
{ url, options },
async (context, { url, options, page }) => await (page || this.fetchPage(url, options))
);
// Load page data
const fetchPromise = this.fetchPage(data);
// create history record if this is not a popstate call (with or without anchor)
if (!this.context.history.popstate) {
const newUrl = url + (this.context.scroll.target || '');
if (this.context.history.action === 'replace') {
updateHistoryRecord(newUrl);
} else {
createHistoryRecord(newUrl);
}
}
// create history record if this is not a popstate call (with or without anchor)
if (!isHistoryVisit) {
const historyUrl = url + (this.scrollToElement || '');
if (historyAction === 'replace') {
updateHistoryRecord(historyUrl);
} else {
createHistoryRecord(historyUrl);
this.currentPageUrl = getCurrentUrl();
// when everything is ready, render the page
const [page] = await Promise.all([pagePromise, animationPromise]);
this.renderPage(requestedUrl, page);
} catch (error: unknown) {
// Return early if error is undefined (probably aborted preload request)
if (!error) {
return;
}
}
this.currentPageUrl = getCurrentUrl();
// Log to console as we swallow almost all hook errors
console.error(error);
// when everything is ready, render the page
Promise.all<PageRecord | void>([fetchPromise, ...animationPromises])
.then(([pageData]) => {
this.renderPage(pageData as PageRecord, { event, skipTransition });
})
.catch((errorUrl) => {
// Return early if errorUrl is not defined (probably aborted preload request)
if (errorUrl === undefined) return;
// Rewrite `skipPopStateHandling` to redirect manually when `history.go` is processed
this.options.skipPopStateHandling = () => {
window.location.href = requestedUrl;
return true;
};
// Rewrite `skipPopStateHandling` to redirect manually when `history.go` is processed
this.options.skipPopStateHandling = () => {
window.location = errorUrl;
return true;
};
// Go back to the actual page we're still at
history.go(-1);
});
// Go back to the actual page we're still at
history.go(-1);
}
}

@@ -1,53 +0,62 @@

import { Location, updateHistoryRecord, getCurrentUrl } from '../helpers.js';
import { updateHistoryRecord, getCurrentUrl } from '../helpers.js';
import Swup from '../Swup.js';
import { PageRecord } from './Cache.js';
import { PageData } from './fetchPage.js';
export type PageRenderOptions = {
event?: PopStateEvent;
skipTransition?: boolean;
};
export const renderPage = async function (this: Swup, requestedUrl: string, page: PageData) {
const { url } = page;
export const renderPage = function (
this: Swup,
page: PageRecord,
{ event, skipTransition }: PageRenderOptions = {}
) {
document.documentElement.classList.remove('is-leaving');
// do nothing if another page was requested in the meantime
if (!this.isSameResolvedUrl(getCurrentUrl(), page.url)) {
if (!this.isSameResolvedUrl(getCurrentUrl(), requestedUrl)) {
return;
}
const { url } = Location.fromUrl(page.responseURL);
// update cache and state if the url was redirected
// update state if the url was redirected
if (!this.isSameResolvedUrl(getCurrentUrl(), url)) {
this.cache.cacheUrl({ ...page, url });
updateHistoryRecord(url);
this.currentPageUrl = getCurrentUrl();
updateHistoryRecord(url);
this.context.to!.url = this.currentPageUrl;
}
// only add for page loads with transitions
if (!skipTransition) {
if (this.context.transition.animate) {
document.documentElement.classList.add('is-rendering');
}
this.triggerEvent('willReplaceContent', event);
// replace content: allow handlers and plugins to overwrite paga data and containers
await this.hooks.trigger(
'replaceContent',
{ page, containers: this.context.containers },
(context, { page, containers }) => {
this.replaceContent(page, { containers });
}
);
this.replaceContent(page).then(() => {
this.triggerEvent('contentReplaced', event);
this.triggerEvent('pageView', event);
// empty cache if it's disabled (in case preload plugin filled it)
if (!this.options.cache) {
this.cache.empty();
await this.hooks.trigger(
'scrollToContent',
{ options: { behavior: 'auto' } },
(context, { options }) => {
if (this.context.scroll.target) {
const target = this.getAnchorElement(this.context.scroll.target);
if (target) {
target.scrollIntoView(options);
return;
}
}
if (this.context.scroll.reset) {
window.scrollTo(0, 0);
}
}
);
// Perform in transition
this.enterPage({ event, skipTransition });
await this.hooks.trigger('pageView', { url: this.currentPageUrl, title: document.title });
// reset scroll-to element
this.scrollToElement = null;
});
// empty cache if it's disabled (in case preload plugin filled it)
if (!this.options.cache) {
this.cache.clear();
}
// Perform in transition
this.enterPage();
};

@@ -0,26 +1,35 @@

import Swup, { Options } from '../Swup.js';
import { PageData } from './fetchPage.js';
/**
* Perform the replacement of content after loading a page.
*
* This method can be replaced or augmented by plugins to allow pausing.
*
* It takes an object with the page data as return from `getPageData` and has to
* return a Promise that resolves once all content has been replaced and the
* site is ready to start animating in the new page.
*
* @param {object} page The page object
* @returns Promise
* It takes an object with the page data as returned from `fetchPage` and a list
* of container selectors to replace.
*/
export const replaceContent = function ({ blocks, title }: { blocks: string[]; title: string }) {
// Replace content blocks
blocks.forEach((html, i) => {
// we know the block exists at this point
const block = document.body.querySelector(`[data-swup="${i}"]`)!;
block.outerHTML = html;
});
export const replaceContent = function (
this: Swup,
{ html }: PageData,
{ containers }: { containers: Options['containers'] } = this.options
): void {
const doc = new DOMParser().parseFromString(html, 'text/html');
// Update browser title
const title = doc.querySelector('title')?.innerText || '';
document.title = title;
// Return a Promise to allow plugins to defer
return Promise.resolve();
// Update content containers
containers.forEach((selector) => {
const currentEl = document.querySelector(selector);
const incomingEl = doc.querySelector(selector);
if (!currentEl) {
console.warn(`[swup] Container missing in current document: ${selector}`);
return;
}
if (!incomingEl) {
console.warn(`[swup] Container missing in incoming document: ${selector}`);
return;
}
currentEl.replaceWith(incomingEl);
});
};

@@ -10,3 +10,2 @@ import { DelegateEvent } from 'delegate-it';

Location,
markSwupElements,
updateHistoryRecord

@@ -17,6 +16,6 @@ } from './helpers.js';

import { Cache } from './modules/Cache.js';
import { Context, createContext } from './modules/Context.js';
import { enterPage } from './modules/enterPage.js';
import { getAnchorElement } from './modules/getAnchorElement.js';
import { getAnimationPromises } from './modules/getAnimationPromises.js';
import { getPageData } from './modules/getPageData.js';
import { fetchPage } from './modules/fetchPage.js';

@@ -26,9 +25,6 @@ import { leavePage } from './modules/leavePage.js';

import { replaceContent } from './modules/replaceContent.js';
import { on, off, triggerEvent, Handlers } from './modules/events.js';
import { Handler, HookName, Hooks } from './modules/Hooks.js';
import { use, unuse, findPlugin, Plugin } from './modules/plugins.js';
import { renderPage } from './modules/renderPage.js';
import { updateTransition, shouldSkipTransition } from './modules/transitions.js';
import { queryAll } from './utils.js';
export type Transition = {

@@ -58,29 +54,3 @@ from?: string;

export default class Swup {
version = version;
_handlers: Handlers = {
animationInDone: [],
animationInStart: [],
animationOutDone: [],
animationOutStart: [],
animationSkipped: [],
clickLink: [],
contentReplaced: [],
disabled: [],
enabled: [],
openPageInNewTab: [],
pageLoaded: [],
pageRetrievedFromCache: [],
pageView: [],
popState: [],
samePage: [],
samePageWithHash: [],
serverError: [],
transitionStart: [],
transitionEnd: [],
willReplaceContent: []
};
// variable for anchor to scroll to after render
scrollToElement: string | null = null;
version: string = version;
// variable for save options

@@ -90,12 +60,12 @@ options: Options;

plugins: Plugin[] = [];
// variable for current transition info object
transition: Transition = {};
// context data
context: Context;
// cache instance
cache: Cache;
// hook registry
hooks: Hooks;
// variable for keeping event listeners from "delegate"
delegatedListeners: DelegatedListeners = {};
// allows us to compare the current and new path inside popStateHandler
currentPageUrl = getCurrentUrl();
// variable for keeping event listeners from "delegate"
delegatedListeners: DelegatedListeners = {};
// so we are able to remove the listener
boundPopStateHandler: (event: PopStateEvent) => void;

@@ -108,10 +78,4 @@ loadPage = loadPage;

enterPage = enterPage;
triggerEvent = triggerEvent;
delegateEvent = delegateEvent;
on = on;
off = off;
updateTransition = updateTransition;
shouldSkipTransition = shouldSkipTransition;
getAnimationPromises = getAnimationPromises;
getPageData = getPageData;
fetchPage = fetchPage;

@@ -125,2 +89,3 @@ getAnchorElement = getAnchorElement;

cleanupAnimationClasses = cleanupAnimationClasses;
createContext = createContext;

@@ -147,24 +112,30 @@ defaults: Options = {

this.boundPopStateHandler = this.popStateHandler.bind(this);
this.linkClickHandler = this.linkClickHandler.bind(this);
this.popStateHandler = this.popStateHandler.bind(this);
this.cache = new Cache(this);
this.hooks = new Hooks(this);
this.context = this.createContext({ to: undefined });
if (!this.checkRequirements()) {
return;
}
this.enable();
}
enable() {
// Check for Promise support
checkRequirements() {
if (typeof Promise === 'undefined') {
console.warn('Promise is not supported');
return;
return false;
}
return true;
}
async enable() {
// Add event listeners
this.delegatedListeners.click = delegateEvent(
this.options.linkSelector,
'click',
this.linkClickHandler.bind(this)
);
const { linkSelector } = this.options;
this.delegatedListeners.click = delegateEvent(linkSelector, 'click', this.linkClickHandler);
window.addEventListener('popstate', this.boundPopStateHandler);
window.addEventListener('popstate', this.popStateHandler);

@@ -177,5 +148,2 @@ // Initial save to cache

// Mark swup blocks in html
markSwupElements(document.documentElement, this.options.containers);
// Mount plugins

@@ -188,12 +156,12 @@ this.options.plugins.forEach((plugin) => this.use(plugin));

// Trigger enabled event
this.triggerEvent('enabled');
await this.hooks.trigger('enabled', undefined, () => {
// Add swup-enabled class to html tag
document.documentElement.classList.add('swup-enabled');
});
// Add swup-enabled class to html tag
document.documentElement.classList.add('swup-enabled');
// Trigger page view event
this.triggerEvent('pageView');
await this.hooks.trigger('pageView', { url: this.currentPageUrl, title: document.title });
}
destroy() {
async destroy() {
// remove delegated listeners

@@ -203,25 +171,18 @@ this.delegatedListeners.click!.destroy();

// remove popstate listener
window.removeEventListener('popstate', this.boundPopStateHandler);
window.removeEventListener('popstate', this.popStateHandler);
// empty cache
this.cache.empty();
this.cache.clear();
// unmount plugins
this.options.plugins.forEach((plugin) => {
this.unuse(plugin);
});
this.options.plugins.forEach((plugin) => this.unuse(plugin));
// remove swup data atributes from blocks
queryAll('[data-swup]').forEach((element) => {
element.removeAttribute('data-swup');
// trigger disable event
await this.hooks.trigger('disabled', undefined, () => {
// remove swup-enabled class from html tag
document.documentElement.classList.remove('swup-enabled');
});
// remove handlers
this.off();
// trigger disable event
this.triggerEvent('disabled');
// remove swup-enabled class from html tag
document.documentElement.classList.remove('swup-enabled');
this.hooks.clear();
}

@@ -252,13 +213,32 @@

linkClickHandler(event: DelegateEvent<MouseEvent>) {
const linkEl = event.delegateTarget;
const { href, url, hash } = Location.fromElement(linkEl as HTMLAnchorElement);
const el = event.delegateTarget as HTMLAnchorElement;
const { href, url, hash } = Location.fromElement(el);
// Get the transition name, if specified
const transition = el.getAttribute('data-swup-transition') || undefined;
// Get the history action, if specified
let historyAction: HistoryAction | undefined;
const historyAttr = el.getAttribute('data-swup-history');
if (historyAttr && ['push', 'replace'].includes(historyAttr)) {
historyAction = historyAttr as HistoryAction;
}
// Exit early if the link should be ignored
if (this.shouldIgnoreVisit(href, { el: linkEl, event })) {
if (this.shouldIgnoreVisit(href, { el, event })) {
return;
}
this.context = this.createContext({
to: url,
hash,
transition,
el,
event,
action: historyAction
});
// Exit early if control key pressed
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
this.triggerEvent('openPageInNewTab', event);
this.hooks.trigger('openPageInNewTab', { href });
return;

@@ -272,51 +252,39 @@ }

this.triggerEvent('clickLink', event);
event.preventDefault();
this.hooks.triggerSync('clickLink', { el, event }, () => {
const from = this.context.from?.url ?? '';
// Handle links to the same page and exit early, where applicable
if (!url || url === getCurrentUrl()) {
this.handleLinkToSamePage(url, hash, event);
return;
}
event.preventDefault();
// Exit early if the resolved path hasn't changed
if (this.isSameResolvedUrl(url, getCurrentUrl())) return;
// Handle links to the same page: with or without hash
if (!url || url === from) {
if (hash) {
updateHistoryRecord(url + hash);
this.hooks.triggerSync(
'samePageWithHash',
{ hash, options: { behavior: 'auto' } },
(context, { hash, options }) => {
const target = this.getAnchorElement(hash);
if (target) {
target.scrollIntoView(options);
}
}
);
} else {
this.hooks.triggerSync('samePage', undefined, () => {
window.scroll({ top: 0, left: 0, behavior: 'auto' });
});
}
return;
}
// Store the element that should be scrolled to after loading the next page
this.scrollToElement = hash || null;
// Exit early if the resolved path hasn't changed
if (this.isSameResolvedUrl(url, from)) {
return;
}
// Get the custom transition name, if present
const customTransition = linkEl.getAttribute('data-swup-transition') || undefined;
// Get the history action, if set
let history: HistoryAction | undefined;
const historyAttr = linkEl.getAttribute('data-swup-history');
if (historyAttr && ['push', 'replace'].includes(historyAttr)) {
history = historyAttr as HistoryAction;
}
// Finally, proceed with loading the page
this.performPageLoad({ url, customTransition, history });
// Finally, proceed with loading the page
this.performPageLoad(url, { transition, history: historyAction });
});
}
handleLinkToSamePage(url: string, hash: string, event: DelegateEvent<MouseEvent>) {
// Emit event and exit early if the url points to the same page without hash
if (!hash) {
this.triggerEvent('samePage', event);
return;
}
// link to the same URL with hash
this.triggerEvent('samePageWithHash', event);
const element = getAnchorElement(hash);
// Warn and exit early if no matching element was found for the hash
if (!element) {
return console.warn(`Element for offset not found (#${hash})`);
}
updateHistoryRecord(url + hash);
}
triggerWillOpenNewWindow(triggerEl: Element) {

@@ -330,2 +298,4 @@ if (triggerEl.matches('[download], [target="_blank"]')) {

popStateHandler(event: PopStateEvent) {
const href = event.state?.url ?? location.href;
// Exit early if this event should be ignored

@@ -341,4 +311,2 @@ if (this.options.skipPopStateHandling(event)) {

const href = event.state?.url ?? location.href;
// Exit early if the link should be ignored

@@ -350,17 +318,21 @@ if (this.shouldIgnoreVisit(href, { event })) {

const { url, hash } = Location.fromUrl(href);
const animate = this.options.animateHistoryBrowsing;
const resetScroll = this.options.animateHistoryBrowsing;
this.context = this.createContext({
to: url,
hash,
event,
animate,
resetScroll,
popstate: true
});
if (hash) {
this.scrollToElement = hash;
} else {
event.preventDefault();
}
// Does this even do anything?
// if (!hash) {
// event.preventDefault();
// }
this.triggerEvent('popState', event);
if (!this.options.animateHistoryBrowsing) {
document.documentElement.classList.remove('is-animating');
cleanupAnimationClasses();
}
this.performPageLoad({ url, event });
this.hooks.triggerSync('popState', { event }, () => {
this.performPageLoad(url);
});
}

@@ -367,0 +339,0 @@

@@ -12,6 +12,8 @@ export const query = (selector: string, context: Document | Element = document) => {

export const nextTick = (callback: () => void) => {
requestAnimationFrame(() => {
export const nextTick = (): Promise<void> => {
return new Promise((resolve) => {
requestAnimationFrame(() => {
callback();
requestAnimationFrame(() => {
resolve();
});
});

@@ -21,2 +23,21 @@ });

export function isPromise<T>(obj: any): obj is PromiseLike<T> {
return (
!!obj &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function'
);
}
export function runAsPromise(func: Function, args: any[] = [], ctx: any = {}): Promise<any> {
return new Promise((resolve, reject) => {
const result = func.apply(ctx, args);
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
});
}
export const escapeCssIdentifier = (ident: string) => {

@@ -23,0 +44,0 @@ // @ts-ignore this is for support check, so it's correct that TS complains

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc