@ionic/core
Version:
Base components for Ionic
4 lines • 10.8 kB
JavaScript
/*!
* (C) Ionic http://ionicframework.com - MIT License
*/
import{c as t,d as n,H as o,i as e,p as i,t as s}from"./p-Ct2aBEue.js";import{c as r,r as a,s as c}from"./p-B4IBdPVJ.js";import{a as u,i as h,g as l}from"./p-V1THdfzs.js";const f="root",d="forward",w=t=>"/"+t.filter((t=>t.length>0)).join("/"),m=t=>{let n,o,e=[""];if(null!=t){const i=t.indexOf("#");i>-1&&(o=t.substring(i+1),t=t.substring(0,i));const s=t.indexOf("?");s>-1&&(n=t.substring(s+1),t=t.substring(0,s)),e=t.split("/").map((t=>t.trim())).filter((t=>t.length>0)),0===e.length&&(e=[""])}return{segments:e,queryString:n,fragment:o}},p=async(n,o,e,i,s=!1,a)=>{try{const t=v(n);if(i>=o.length||!t)return s;await new Promise((n=>r(t,n)));const c=o[i],u=await t.setRouteId(c.id,c.params,e,a);return u.changed&&(e=f,s=!0),s=await p(u.element,o,e,i+1,s,a),u.markVisible&&await u.markVisible(),s}catch(n){return t("[ion-router] - Exception in writeNavState:",n),!1}},g=()=>new Promise((t=>a((()=>t())))),y=t=>{const n=t.closest(".ion-page");return null===n?null===document.querySelector(".ion-page"):null===n.closest(".ion-page-hidden, .tab-hidden")},b=":not([no-router]) ion-tabs, :not([no-router]) ion-router-outlet",v=t=>{if(t)return t.matches(b)?t:t.querySelector(b)??void 0},R=(t,n)=>n.find((n=>((t,n)=>{const{from:o,to:e}=n;if(void 0===e)return!1;if(o.length>t.length)return!1;for(let n=0;n<o.length;n++){const e=o[n];if("*"===e)return!0;if(e!==t[n])return!1}return o.length===t.length})(t,n))),S=(t,n)=>{const o=Math.min(t.length,n.length);let e=0;for(let i=0;i<o;i++){const o=t[i],s=n[i];if(o.id.toLowerCase()!==s.id)break;if(o.params){const t=Object.keys(o.params);if(t.length===s.segments.length){const n=t.map((t=>":"+t));for(let t=0;t<n.length&&n[t].toLowerCase()===s.segments[t];t++)e++}}e++}return e},E=(t,n)=>{const o=new N(t);let e,i=!1;for(let t=0;t<n.length;t++){const s=n[t].segments;if(""===s[0])i=!0;else{for(const n of s){const i=o.next();if(":"===n[0]){if(""===i)return null;e=e||[],(e[t]||(e[t]={}))[n.slice(1)]=i}else if(i!==n)return null}i=!1}}return i&&i!==(""===o.next())?null:e?n.map(((t,n)=>({id:t.id,segments:t.segments,params:C(t.params,e[n]),beforeEnter:t.beforeEnter,beforeLeave:t.beforeLeave}))):n},C=(t,n)=>t||n?{...t,...n}:void 0,T=(t,n)=>{let o=null,e=0;for(const i of n){const n=E(t,i);if(null!==n){const t=L(n);t>e&&(e=t,o=n)}}return o},L=t=>{let n=1,o=1;for(const e of t)for(const t of e.segments)":"===t[0]?n+=Math.pow(1,o):""!==t&&(n+=Math.pow(2,o)),o++;return n};class N{constructor(t){this.segments=t.slice()}next(){return this.segments.length>0?this.segments.shift():""}}const j=(t,n)=>n in t?t[n]:t.hasAttribute(n)?t.getAttribute(n):null,k=t=>Array.from(t.children).filter((t=>"ION-ROUTE-REDIRECT"===t.tagName)).map((t=>{const n=j(t,"to");return{from:m(j(t,"from")).segments,to:null==n?void 0:m(n)}})),B=t=>D(P(t)),P=t=>Array.from(t.children).filter((t=>"ION-ROUTE"===t.tagName&&!!t.component)).map((t=>{const n=j(t,"component");return{segments:m(j(t,"url")).segments,id:n.toLowerCase(),params:t.componentProps,beforeLeave:t.beforeLeave,beforeEnter:t.beforeEnter,children:P(t)}})),D=t=>{const n=[];for(const o of t)O([],n,o);return n},O=(t,n,o)=>{if(t=[...t,{id:o.id,segments:o.segments,params:o.params,beforeLeave:o.beforeLeave,beforeEnter:o.beforeEnter}],0!==o.children.length)for(const e of o.children)O(t,n,e);else n.push(t)},x=n(class extends o{constructor(t){super(),!1!==t&&this.__registerHost(),this.ionRouteWillChange=e(this,"ionRouteWillChange",7),this.ionRouteDidChange=e(this,"ionRouteDidChange",7),this.previousPath=null,this.busy=!1,this.state=0,this.lastState=0,this.fragmentScrollToken=0,this.root="/",this.useHash=!0}async componentWillLoad(){await(v(document.body)?Promise.resolve():new Promise((t=>{const n=()=>{window.removeEventListener("ionNavWillLoad",n),clearTimeout(o),t()},o=setTimeout(n,500);window.addEventListener("ionNavWillLoad",n,{once:!0})})));const t=await this.runGuards(this.getSegments());if(!0===t)await this.onRoutesChanged()&&this.maybeScrollToFragment();else if("object"==typeof t){const{redirect:n}=t,o=m(n);this.setSegments(o.segments,f,o.queryString,o.fragment),await this.writeNavStateRoot(o.segments,f)&&this.maybeScrollToFragment()}}componentDidLoad(){window.addEventListener("ionRouteRedirectChanged",c(this.onRedirectChanged.bind(this),10)),window.addEventListener("ionRouteDataChanged",c(this.onRoutesChanged.bind(this),100))}async onPopState(){const t=this.historyDirection();let n=this.getSegments();const o=await this.runGuards(n);if(!0!==o){if("object"!=typeof o)return!1;n=m(o.redirect).segments}const e=await this.writeNavStateRoot(n,t);return e&&this.maybeScrollToFragment(),e}onBackButton(t){t.detail.register(0,(t=>{this.back(),t()}))}async canTransition(){const t=await this.runGuards();return!0===t||"object"==typeof t&&t.redirect}async push(t,n="forward",o){if(t.startsWith(".")){const n=new URL(t,"https://host/"+(this.previousPath??"/"));t=n.pathname+n.search+n.hash}let e=m(t);const i=await this.runGuards(e.segments);if(!0!==i){if("object"!=typeof i)return!1;e=m(i.redirect)}this.setSegments(e.segments,n,e.queryString,e.fragment);const s=await this.writeNavStateRoot(e.segments,n,o);return s&&this.maybeScrollToFragment(),s}back(){return window.history.back(),Promise.resolve(this.waitPromise)}async printDebug(){(t=>{console.group(`[ion-core] ROUTES[${t.length}]`);for(const n of t){const t=[];n.forEach((n=>t.push(...n.segments)));const o=n.map((t=>t.id));console.debug("%c "+w(t),"font-weight: bold; padding-left: 20px","=>\t",`(${o.join(", ")})`)}console.groupEnd()})(B(this.el)),(t=>{console.group(`[ion-core] REDIRECTS[${t.length}]`);for(const n of t)n.to&&console.debug("FROM: ","$c "+w(n.from),"font-weight: bold"," TO: ","$c "+w(n.to.segments),"font-weight: bold");console.groupEnd()})(k(this.el))}async navChanged(t){if(this.busy)return i("[ion-router] - Router is busy, navChanged was cancelled."),!1;const{ids:n,outlet:o}=await(async()=>{const t=[];let n,o=window.document.body;for(;n=v(o);){const e=await n.getRouteId();if(!e)break;o=e.element,e.element=void 0,t.push(e)}return{ids:t,outlet:n}})(),e=((t,n)=>{let o=null,e=0;for(const i of n){const n=S(t,i);n>e&&(o=i,e=n)}return o?o.map(((n,o)=>({id:n.id,segments:n.segments,params:C(n.params,t[o]?.params)}))):null})(n,B(this.el));if(!e)return i("[ion-router] - No matching URL for",n.map((t=>t.id))),!1;const s=(t=>{const n=[];for(const o of t)for(const t of o.segments)if(":"===t[0]){const e=o.params&&o.params[t.slice(1)];if(!e)return null;n.push(e)}else""!==t&&n.push(t);return n})(e);if(!s)return i("[ion-router] - Router could not match path because some required param is missing."),!1;const r=w(s)===this.previousPath?this.getFragment():void 0;return this.setSegments(s,t,void 0,r),await this.safeWriteNavState(o,e,f,s,null,n.length),!0}onRedirectChanged(){const t=this.getSegments();t&&R(t,k(this.el))&&this.writeNavStateRoot(t,f)}onRoutesChanged(){return this.writeNavStateRoot(this.getSegments(),f)}historyDirection(){const t=window;null===t.history.state&&(this.state++,t.history.replaceState(this.state,t.document.title,t.document.location?.href));const n=t.history.state,o=this.lastState;return this.lastState=n,n>o||n>=o&&o>0?d:n<o?"back":f}async writeNavStateRoot(n,o,e){if(!n)return t("[ion-router] - URL is not part of the routing set."),!1;const i=k(this.el),s=R(n,i);let r=null;if(s){const{segments:t,queryString:e,fragment:i}=s.to;this.setSegments(t,o,e,i),r=s.from,n=t}const a=B(this.el),c=T(n,a);return c?this.safeWriteNavState(document.body,c,o,n,r,0,e):(t("[ion-router] - The path does not match any route."),!1)}async safeWriteNavState(n,o,e,i,s,r=0,a){const c=await this.lock();let u=!1;try{u=await this.writeNavState(n,o,e,i,s,r,a)}catch(n){t("[ion-router] - Exception in safeWriteNavState:",n)}return c(),u}async lock(){const t=this.waitPromise;let n;return this.waitPromise=new Promise((t=>n=t)),void 0!==t&&await t,n}async runGuards(t=this.getSegments(),n){if(void 0===n&&(n=m(this.previousPath).segments),!t||!n)return!0;const o=B(this.el),e=T(n,o),i=e&&e[e.length-1].beforeLeave,s=!i||await i();if(!1===s||"object"==typeof s)return s;const r=T(t,o),a=r&&r[r.length-1].beforeEnter;return!a||a()}async writeNavState(t,n,o,e,s,r=0,a){if(this.busy)return i("[ion-router] - Router is busy, transition was cancelled."),!1;this.busy=!0;const c=this.routeChangeEvent(e,s);c&&this.ionRouteWillChange.emit(c);const u=await p(t,n,o,r,!1,a);return this.busy=!1,c&&this.ionRouteDidChange.emit(c),u}setSegments(t,n,o,e){this.state++,this.fragmentScrollToken++,((t,n,o,e,i,s,r,a)=>{const c=((t,n,o,e)=>{let i=w(t);return n&&(i="#"+i),void 0!==o&&(i+="?"+o),void 0!==e&&(i+="#"+e),i})([...m(n).segments,...e],o,r,a);i===d?t.pushState(s,"",c):t.replaceState(s,"",c)})(window.history,this.root,this.useHash,t,n,this.state,o,e)}getSegments(){return((t,n,o)=>{const e=m(this.root).segments,i=o?t.hash.slice(1):t.pathname;return((t,n)=>{if(t.length>n.length)return null;if(t.length<=1&&""===t[0])return n;for(let o=0;o<t.length;o++)if(t[o]!==n[o])return null;return n.length===t.length?[""]:n.slice(t.length)})(e,m(i).segments)})(window.location,0,this.useHash)}getFragment(){return(this.useHash?m(window.location.hash.slice(1)).fragment:window.location.hash.slice(1))||void 0}maybeScrollToFragment(){const n=this.getFragment();if(!n)return;const o=this.fragmentScrollToken;(async(n,o=()=>!0)=>{if(null==n||""===n)return!1;let e;try{e=decodeURIComponent(n)}catch{e=n}const i=await(async(t,n)=>{const o="undefined"!=typeof CSS&&"function"==typeof CSS.escape?CSS.escape(t):null;for(let e=0;e<30;e++){if(!n())return null;let e=[];if(null!==o)try{e=[...document.querySelectorAll(`#${o}, a[name="${o}"]`)]}catch{e=[...document.querySelectorAll("#"+o)]}else{const n=document.getElementById(t);null!==n&&(e=[n])}for(let t=e.length-1;t>=0;t--)if(y(e[t]))return e[t];await g()}return null})(e,o);if(!i||!o())return!1;try{const t=u(i);if(t&&h(t)){const n=t,e=await l(n);if(await g(),!o())return!1;const s=i.getBoundingClientRect(),r=e.getBoundingClientRect(),a=s.top-r.top+e.scrollTop;await n.scrollToPoint(e.scrollLeft,a,300)}else i.scrollIntoView({behavior:"smooth"});return!0}catch(n){return t("[ion-router] - Exception in scrollToFragment:",n),!1}})(n,(()=>o===this.fragmentScrollToken)).catch((()=>{}))}routeChangeEvent(t,n){const o=this.previousPath,e=w(t);return this.previousPath=e,e===o?null:{from:o,redirectedFrom:n?w(n):null,to:e}}get el(){return this}},[0,"ion-router",{root:[1],useHash:[4,"use-hash"],canTransition:[64],push:[64],back:[64],printDebug:[64],navChanged:[64]},[[8,"popstate","onPopState"],[4,"ionBackButton","onBackButton"]]]),U=x,$=function(){"undefined"!=typeof customElements&&["ion-router"].forEach((t=>{"ion-router"===t&&(customElements.get(s(t))||customElements.define(s(t),x))}))};export{U as IonRouter,$ as defineCustomElement}