1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | const index = require('./index-a0a08b2a.js');
|
6 | const helpers = require('./helpers-d381ec4d.js');
|
7 | const ionicGlobal = require('./ionic-global-06f21c1a.js');
|
8 | const theme = require('./theme-30b7a575.js');
|
9 |
|
10 | const Route = class {
|
11 | constructor(hostRef) {
|
12 | index.registerInstance(this, hostRef);
|
13 | this.ionRouteDataChanged = index.createEvent(this, "ionRouteDataChanged", 7);
|
14 | |
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | this.url = '';
|
21 | }
|
22 | onUpdate(newValue) {
|
23 | this.ionRouteDataChanged.emit(newValue);
|
24 | }
|
25 | onComponentProps(newValue, oldValue) {
|
26 | if (newValue === oldValue) {
|
27 | return;
|
28 | }
|
29 | const keys1 = newValue ? Object.keys(newValue) : [];
|
30 | const keys2 = oldValue ? Object.keys(oldValue) : [];
|
31 | if (keys1.length !== keys2.length) {
|
32 | this.onUpdate(newValue);
|
33 | return;
|
34 | }
|
35 | for (const key of keys1) {
|
36 | if (newValue[key] !== oldValue[key]) {
|
37 | this.onUpdate(newValue);
|
38 | return;
|
39 | }
|
40 | }
|
41 | }
|
42 | connectedCallback() {
|
43 | this.ionRouteDataChanged.emit();
|
44 | }
|
45 | static get watchers() { return {
|
46 | "url": ["onUpdate"],
|
47 | "component": ["onUpdate"],
|
48 | "componentProps": ["onComponentProps"]
|
49 | }; }
|
50 | };
|
51 |
|
52 | const RouteRedirect = class {
|
53 | constructor(hostRef) {
|
54 | index.registerInstance(this, hostRef);
|
55 | this.ionRouteRedirectChanged = index.createEvent(this, "ionRouteRedirectChanged", 7);
|
56 | }
|
57 | propDidChange() {
|
58 | this.ionRouteRedirectChanged.emit();
|
59 | }
|
60 | connectedCallback() {
|
61 | this.ionRouteRedirectChanged.emit();
|
62 | }
|
63 | static get watchers() { return {
|
64 | "from": ["propDidChange"],
|
65 | "to": ["propDidChange"]
|
66 | }; }
|
67 | };
|
68 |
|
69 | const ROUTER_INTENT_NONE = 'root';
|
70 | const ROUTER_INTENT_FORWARD = 'forward';
|
71 | const ROUTER_INTENT_BACK = 'back';
|
72 |
|
73 |
|
74 | const generatePath = (segments) => {
|
75 | const path = segments
|
76 | .filter(s => s.length > 0)
|
77 | .join('/');
|
78 | return '/' + path;
|
79 | };
|
80 | const generateUrl = (segments, useHash, queryString) => {
|
81 | let url = generatePath(segments);
|
82 | if (useHash) {
|
83 | url = '#' + url;
|
84 | }
|
85 | if (queryString !== undefined) {
|
86 | url += '?' + queryString;
|
87 | }
|
88 | return url;
|
89 | };
|
90 | const writePath = (history, root, useHash, path, direction, state, queryString) => {
|
91 | const url = generateUrl([...parsePath(root).segments, ...path], useHash, queryString);
|
92 | if (direction === ROUTER_INTENT_FORWARD) {
|
93 | history.pushState(state, '', url);
|
94 | }
|
95 | else {
|
96 | history.replaceState(state, '', url);
|
97 | }
|
98 | };
|
99 | const chainToPath = (chain) => {
|
100 | const path = [];
|
101 | for (const route of chain) {
|
102 | for (const segment of route.path) {
|
103 | if (segment[0] === ':') {
|
104 | const param = route.params && route.params[segment.slice(1)];
|
105 | if (!param) {
|
106 | return null;
|
107 | }
|
108 | path.push(param);
|
109 | }
|
110 | else if (segment !== '') {
|
111 | path.push(segment);
|
112 | }
|
113 | }
|
114 | }
|
115 | return path;
|
116 | };
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | const removePrefix = (prefix, path) => {
|
123 | if (prefix.length > path.length) {
|
124 | return null;
|
125 | }
|
126 | if (prefix.length <= 1 && prefix[0] === '') {
|
127 | return path;
|
128 | }
|
129 | for (let i = 0; i < prefix.length; i++) {
|
130 | if (prefix[i] !== path[i]) {
|
131 | return null;
|
132 | }
|
133 | }
|
134 | if (path.length === prefix.length) {
|
135 | return [''];
|
136 | }
|
137 | return path.slice(prefix.length);
|
138 | };
|
139 | const readPath = (loc, root, useHash) => {
|
140 | const prefix = parsePath(root).segments;
|
141 | const pathname = useHash ? loc.hash.slice(1) : loc.pathname;
|
142 | const path = parsePath(pathname).segments;
|
143 | return removePrefix(prefix, path);
|
144 | };
|
145 |
|
146 |
|
147 |
|
148 | const parsePath = (path) => {
|
149 | let segments = [''];
|
150 | let queryString;
|
151 | if (path != null) {
|
152 | const qsStart = path.indexOf('?');
|
153 | if (qsStart > -1) {
|
154 | queryString = path.substr(qsStart + 1);
|
155 | path = path.substr(0, qsStart);
|
156 | }
|
157 | segments = path.split('/')
|
158 | .map(s => s.trim())
|
159 | .filter(s => s.length > 0);
|
160 | if (segments.length === 0) {
|
161 | segments = [''];
|
162 | }
|
163 | }
|
164 | return { segments, queryString };
|
165 | };
|
166 |
|
167 | const printRoutes = (routes) => {
|
168 | console.group(`[ion-core] ROUTES[${routes.length}]`);
|
169 | for (const chain of routes) {
|
170 | const path = [];
|
171 | chain.forEach(r => path.push(...r.path));
|
172 | const ids = chain.map(r => r.id);
|
173 | console.debug(`%c ${generatePath(path)}`, 'font-weight: bold; padding-left: 20px', '=>\t', `(${ids.join(', ')})`);
|
174 | }
|
175 | console.groupEnd();
|
176 | };
|
177 | const printRedirects = (redirects) => {
|
178 | console.group(`[ion-core] REDIRECTS[${redirects.length}]`);
|
179 | for (const redirect of redirects) {
|
180 | if (redirect.to) {
|
181 | console.debug('FROM: ', `$c ${generatePath(redirect.from)}`, 'font-weight: bold', ' TO: ', `$c ${generatePath(redirect.to.segments)}`, 'font-weight: bold');
|
182 | }
|
183 | }
|
184 | console.groupEnd();
|
185 | };
|
186 |
|
187 | const writeNavState = async (root, chain, direction, index, changed = false, animation) => {
|
188 | try {
|
189 |
|
190 | const outlet = searchNavNode(root);
|
191 |
|
192 | if (index >= chain.length || !outlet) {
|
193 | return changed;
|
194 | }
|
195 | await new Promise(resolve => helpers.componentOnReady(outlet, resolve));
|
196 | const route = chain[index];
|
197 | const result = await outlet.setRouteId(route.id, route.params, direction, animation);
|
198 |
|
199 |
|
200 | if (result.changed) {
|
201 | direction = ROUTER_INTENT_NONE;
|
202 | changed = true;
|
203 | }
|
204 |
|
205 | changed = await writeNavState(result.element, chain, direction, index + 1, changed, animation);
|
206 |
|
207 |
|
208 | if (result.markVisible) {
|
209 | await result.markVisible();
|
210 | }
|
211 | return changed;
|
212 | }
|
213 | catch (e) {
|
214 | console.error(e);
|
215 | return false;
|
216 | }
|
217 | };
|
218 | const readNavState = async (root) => {
|
219 | const ids = [];
|
220 | let outlet;
|
221 | let node = root;
|
222 |
|
223 | while (true) {
|
224 | outlet = searchNavNode(node);
|
225 | if (outlet) {
|
226 | const id = await outlet.getRouteId();
|
227 | if (id) {
|
228 | node = id.element;
|
229 | id.element = undefined;
|
230 | ids.push(id);
|
231 | }
|
232 | else {
|
233 | break;
|
234 | }
|
235 | }
|
236 | else {
|
237 | break;
|
238 | }
|
239 | }
|
240 | return { ids, outlet };
|
241 | };
|
242 | const waitUntilNavNode = () => {
|
243 | if (searchNavNode(document.body)) {
|
244 | return Promise.resolve();
|
245 | }
|
246 | return new Promise(resolve => {
|
247 | window.addEventListener('ionNavWillLoad', resolve, { once: true });
|
248 | });
|
249 | };
|
250 | const QUERY = ':not([no-router]) ion-nav, :not([no-router]) ion-tabs, :not([no-router]) ion-router-outlet';
|
251 | const searchNavNode = (root) => {
|
252 | if (!root) {
|
253 | return undefined;
|
254 | }
|
255 | if (root.matches(QUERY)) {
|
256 | return root;
|
257 | }
|
258 | const outlet = root.querySelector(QUERY);
|
259 | return outlet !== null && outlet !== void 0 ? outlet : undefined;
|
260 | };
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 | const matchesRedirect = (path, redirect) => {
|
268 | const { from, to } = redirect;
|
269 | if (to === undefined) {
|
270 | return false;
|
271 | }
|
272 | if (from.length > path.length) {
|
273 | return false;
|
274 | }
|
275 | for (let i = 0; i < from.length; i++) {
|
276 | const expected = from[i];
|
277 | if (expected === '*') {
|
278 | return true;
|
279 | }
|
280 | if (expected !== path[i]) {
|
281 | return false;
|
282 | }
|
283 | }
|
284 | return from.length === path.length;
|
285 | };
|
286 |
|
287 | const findRouteRedirect = (path, redirects) => {
|
288 | return redirects.find(redirect => matchesRedirect(path, redirect));
|
289 | };
|
290 | const matchesIDs = (ids, chain) => {
|
291 | const len = Math.min(ids.length, chain.length);
|
292 | let i = 0;
|
293 | for (; i < len; i++) {
|
294 | if (ids[i].toLowerCase() !== chain[i].id) {
|
295 | break;
|
296 | }
|
297 | }
|
298 | return i;
|
299 | };
|
300 | const matchesPath = (inputPath, chain) => {
|
301 | const segments = new RouterSegments(inputPath);
|
302 | let matchesDefault = false;
|
303 | let allparams;
|
304 | for (let i = 0; i < chain.length; i++) {
|
305 | const path = chain[i].path;
|
306 | if (path[0] === '') {
|
307 | matchesDefault = true;
|
308 | }
|
309 | else {
|
310 | for (const segment of path) {
|
311 | const data = segments.next();
|
312 |
|
313 | if (segment[0] === ':') {
|
314 | if (data === '') {
|
315 | return null;
|
316 | }
|
317 | allparams = allparams || [];
|
318 | const params = allparams[i] || (allparams[i] = {});
|
319 | params[segment.slice(1)] = data;
|
320 | }
|
321 | else if (data !== segment) {
|
322 | return null;
|
323 | }
|
324 | }
|
325 | matchesDefault = false;
|
326 | }
|
327 | }
|
328 | const matches = (matchesDefault)
|
329 | ? matchesDefault === (segments.next() === '')
|
330 | : true;
|
331 | if (!matches) {
|
332 | return null;
|
333 | }
|
334 | if (allparams) {
|
335 | return chain.map((route, i) => ({
|
336 | id: route.id,
|
337 | path: route.path,
|
338 | params: mergeParams(route.params, allparams[i]),
|
339 | beforeEnter: route.beforeEnter,
|
340 | beforeLeave: route.beforeLeave
|
341 | }));
|
342 | }
|
343 | return chain;
|
344 | };
|
345 |
|
346 |
|
347 | const mergeParams = (a, b) => {
|
348 | return a || b ? Object.assign(Object.assign({}, a), b) : undefined;
|
349 | };
|
350 | const routerIDsToChain = (ids, chains) => {
|
351 | let match = null;
|
352 | let maxMatches = 0;
|
353 | const plainIDs = ids.map(i => i.id);
|
354 | for (const chain of chains) {
|
355 | const score = matchesIDs(plainIDs, chain);
|
356 | if (score > maxMatches) {
|
357 | match = chain;
|
358 | maxMatches = score;
|
359 | }
|
360 | }
|
361 | if (match) {
|
362 | return match.map((route, i) => ({
|
363 | id: route.id,
|
364 | path: route.path,
|
365 | params: mergeParams(route.params, ids[i] && ids[i].params)
|
366 | }));
|
367 | }
|
368 | return null;
|
369 | };
|
370 | const routerPathToChain = (path, chains) => {
|
371 | let match = null;
|
372 | let matches = 0;
|
373 | for (const chain of chains) {
|
374 | const matchedChain = matchesPath(path, chain);
|
375 | if (matchedChain !== null) {
|
376 | const score = computePriority(matchedChain);
|
377 | if (score > matches) {
|
378 | matches = score;
|
379 | match = matchedChain;
|
380 | }
|
381 | }
|
382 | }
|
383 | return match;
|
384 | };
|
385 | const computePriority = (chain) => {
|
386 | let score = 1;
|
387 | let level = 1;
|
388 | for (const route of chain) {
|
389 | for (const path of route.path) {
|
390 | if (path[0] === ':') {
|
391 | score += Math.pow(1, level);
|
392 | }
|
393 | else if (path !== '') {
|
394 | score += Math.pow(2, level);
|
395 | }
|
396 | level++;
|
397 | }
|
398 | }
|
399 | return score;
|
400 | };
|
401 | class RouterSegments {
|
402 | constructor(path) {
|
403 | this.path = path.slice();
|
404 | }
|
405 | next() {
|
406 | if (this.path.length > 0) {
|
407 | return this.path.shift();
|
408 | }
|
409 | return '';
|
410 | }
|
411 | }
|
412 |
|
413 | const readProp = (el, prop) => {
|
414 | if (prop in el) {
|
415 | return el[prop];
|
416 | }
|
417 | if (el.hasAttribute(prop)) {
|
418 | return el.getAttribute(prop);
|
419 | }
|
420 | return null;
|
421 | };
|
422 | const readRedirects = (root) => {
|
423 | return Array.from(root.children)
|
424 | .filter(el => el.tagName === 'ION-ROUTE-REDIRECT')
|
425 | .map(el => {
|
426 | const to = readProp(el, 'to');
|
427 | return {
|
428 | from: parsePath(readProp(el, 'from')).segments,
|
429 | to: to == null ? undefined : parsePath(to),
|
430 | };
|
431 | });
|
432 | };
|
433 | const readRoutes = (root) => {
|
434 | return flattenRouterTree(readRouteNodes(root));
|
435 | };
|
436 | const readRouteNodes = (node) => {
|
437 | return Array.from(node.children)
|
438 | .filter(el => el.tagName === 'ION-ROUTE' && el.component)
|
439 | .map(el => {
|
440 | const component = readProp(el, 'component');
|
441 | return {
|
442 | path: parsePath(readProp(el, 'url')).segments,
|
443 | id: component.toLowerCase(),
|
444 | params: el.componentProps,
|
445 | beforeLeave: el.beforeLeave,
|
446 | beforeEnter: el.beforeEnter,
|
447 | children: readRouteNodes(el)
|
448 | };
|
449 | });
|
450 | };
|
451 | const flattenRouterTree = (nodes) => {
|
452 | const chains = [];
|
453 | for (const node of nodes) {
|
454 | flattenNode([], chains, node);
|
455 | }
|
456 | return chains;
|
457 | };
|
458 | const flattenNode = (chain, chains, node) => {
|
459 | chain = chain.slice();
|
460 | chain.push({
|
461 | id: node.id,
|
462 | path: node.path,
|
463 | params: node.params,
|
464 | beforeLeave: node.beforeLeave,
|
465 | beforeEnter: node.beforeEnter
|
466 | });
|
467 | if (node.children.length === 0) {
|
468 | chains.push(chain);
|
469 | return;
|
470 | }
|
471 | for (const child of node.children) {
|
472 | flattenNode(chain, chains, child);
|
473 | }
|
474 | };
|
475 |
|
476 | const Router = class {
|
477 | constructor(hostRef) {
|
478 | index.registerInstance(this, hostRef);
|
479 | this.ionRouteWillChange = index.createEvent(this, "ionRouteWillChange", 7);
|
480 | this.ionRouteDidChange = index.createEvent(this, "ionRouteDidChange", 7);
|
481 | this.previousPath = null;
|
482 | this.busy = false;
|
483 | this.state = 0;
|
484 | this.lastState = 0;
|
485 | |
486 |
|
487 |
|
488 |
|
489 |
|
490 | this.root = '/';
|
491 | |
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 | this.useHash = true;
|
506 | }
|
507 | async componentWillLoad() {
|
508 | await waitUntilNavNode();
|
509 | const canProceed = await this.runGuards(this.getPath());
|
510 | if (canProceed !== true) {
|
511 | if (typeof canProceed === 'object') {
|
512 | const { redirect } = canProceed;
|
513 | const path = parsePath(redirect);
|
514 | this.setPath(path.segments, ROUTER_INTENT_NONE, path.queryString);
|
515 | await this.writeNavStateRoot(path.segments, ROUTER_INTENT_NONE);
|
516 | }
|
517 | }
|
518 | else {
|
519 | await this.onRoutesChanged();
|
520 | }
|
521 | }
|
522 | componentDidLoad() {
|
523 | window.addEventListener('ionRouteRedirectChanged', helpers.debounce(this.onRedirectChanged.bind(this), 10));
|
524 | window.addEventListener('ionRouteDataChanged', helpers.debounce(this.onRoutesChanged.bind(this), 100));
|
525 | }
|
526 | async onPopState() {
|
527 | const direction = this.historyDirection();
|
528 | let segments = this.getPath();
|
529 | const canProceed = await this.runGuards(segments);
|
530 | if (canProceed !== true) {
|
531 | if (typeof canProceed === 'object') {
|
532 | segments = parsePath(canProceed.redirect).segments;
|
533 | }
|
534 | else {
|
535 | return false;
|
536 | }
|
537 | }
|
538 | return this.writeNavStateRoot(segments, direction);
|
539 | }
|
540 | onBackButton(ev) {
|
541 | ev.detail.register(0, processNextHandler => {
|
542 | this.back();
|
543 | processNextHandler();
|
544 | });
|
545 | }
|
546 |
|
547 | async canTransition() {
|
548 | const canProceed = await this.runGuards();
|
549 | if (canProceed !== true) {
|
550 | if (typeof canProceed === 'object') {
|
551 | return canProceed.redirect;
|
552 | }
|
553 | else {
|
554 | return false;
|
555 | }
|
556 | }
|
557 | return true;
|
558 | }
|
559 | |
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 | async push(url, direction = 'forward', animation) {
|
566 | if (url.startsWith('.')) {
|
567 | url = (new URL(url, window.location.href)).pathname;
|
568 | }
|
569 | let parsedPath = parsePath(url);
|
570 | const canProceed = await this.runGuards(parsedPath.segments);
|
571 | if (canProceed !== true) {
|
572 | if (typeof canProceed === 'object') {
|
573 | parsedPath = parsePath(canProceed.redirect);
|
574 | }
|
575 | else {
|
576 | return false;
|
577 | }
|
578 | }
|
579 | this.setPath(parsedPath.segments, direction, parsedPath.queryString);
|
580 | return this.writeNavStateRoot(parsedPath.segments, direction, animation);
|
581 | }
|
582 | |
583 |
|
584 |
|
585 | back() {
|
586 | window.history.back();
|
587 | return Promise.resolve(this.waitPromise);
|
588 | }
|
589 |
|
590 | async printDebug() {
|
591 | printRoutes(readRoutes(this.el));
|
592 | printRedirects(readRedirects(this.el));
|
593 | }
|
594 |
|
595 | async navChanged(direction) {
|
596 | if (this.busy) {
|
597 | console.warn('[ion-router] router is busy, navChanged was cancelled');
|
598 | return false;
|
599 | }
|
600 | const { ids, outlet } = await readNavState(window.document.body);
|
601 | const routes = readRoutes(this.el);
|
602 | const chain = routerIDsToChain(ids, routes);
|
603 | if (!chain) {
|
604 | console.warn('[ion-router] no matching URL for ', ids.map(i => i.id));
|
605 | return false;
|
606 | }
|
607 | const path = chainToPath(chain);
|
608 | if (!path) {
|
609 | console.warn('[ion-router] router could not match path because some required param is missing');
|
610 | return false;
|
611 | }
|
612 | this.setPath(path, direction);
|
613 | await this.safeWriteNavState(outlet, chain, ROUTER_INTENT_NONE, path, null, ids.length);
|
614 | return true;
|
615 | }
|
616 |
|
617 | onRedirectChanged() {
|
618 | const path = this.getPath();
|
619 | if (path && findRouteRedirect(path, readRedirects(this.el))) {
|
620 | this.writeNavStateRoot(path, ROUTER_INTENT_NONE);
|
621 | }
|
622 | }
|
623 |
|
624 | onRoutesChanged() {
|
625 | return this.writeNavStateRoot(this.getPath(), ROUTER_INTENT_NONE);
|
626 | }
|
627 | historyDirection() {
|
628 | var _a;
|
629 | const win = window;
|
630 | if (win.history.state === null) {
|
631 | this.state++;
|
632 | win.history.replaceState(this.state, win.document.title, (_a = win.document.location) === null || _a === void 0 ? void 0 : _a.href);
|
633 | }
|
634 | const state = win.history.state;
|
635 | const lastState = this.lastState;
|
636 | this.lastState = state;
|
637 | if (state > lastState || (state >= lastState && lastState > 0)) {
|
638 | return ROUTER_INTENT_FORWARD;
|
639 | }
|
640 | if (state < lastState) {
|
641 | return ROUTER_INTENT_BACK;
|
642 | }
|
643 | return ROUTER_INTENT_NONE;
|
644 | }
|
645 | async writeNavStateRoot(path, direction, animation) {
|
646 | if (!path) {
|
647 | console.error('[ion-router] URL is not part of the routing set');
|
648 | return false;
|
649 | }
|
650 |
|
651 | const redirects = readRedirects(this.el);
|
652 | const redirect = findRouteRedirect(path, redirects);
|
653 | let redirectFrom = null;
|
654 | if (redirect) {
|
655 | const { segments, queryString } = redirect.to;
|
656 | this.setPath(segments, direction, queryString);
|
657 | redirectFrom = redirect.from;
|
658 | path = segments;
|
659 | }
|
660 |
|
661 | const routes = readRoutes(this.el);
|
662 | const chain = routerPathToChain(path, routes);
|
663 | if (!chain) {
|
664 | console.error('[ion-router] the path does not match any route');
|
665 | return false;
|
666 | }
|
667 |
|
668 | return this.safeWriteNavState(document.body, chain, direction, path, redirectFrom, 0, animation);
|
669 | }
|
670 | async safeWriteNavState(node, chain, direction, path, redirectFrom, index = 0, animation) {
|
671 | const unlock = await this.lock();
|
672 | let changed = false;
|
673 | try {
|
674 | changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index, animation);
|
675 | }
|
676 | catch (e) {
|
677 | console.error(e);
|
678 | }
|
679 | unlock();
|
680 | return changed;
|
681 | }
|
682 | async lock() {
|
683 | const p = this.waitPromise;
|
684 | let resolve;
|
685 | this.waitPromise = new Promise(r => resolve = r);
|
686 | if (p !== undefined) {
|
687 | await p;
|
688 | }
|
689 | return resolve;
|
690 | }
|
691 |
|
692 |
|
693 |
|
694 |
|
695 | async runGuards(to = this.getPath(), from) {
|
696 | if (from === undefined) {
|
697 | from = parsePath(this.previousPath).segments;
|
698 | }
|
699 | if (!to || !from) {
|
700 | return true;
|
701 | }
|
702 | const routes = readRoutes(this.el);
|
703 | const fromChain = routerPathToChain(from, routes);
|
704 | const beforeLeaveHook = fromChain && fromChain[fromChain.length - 1].beforeLeave;
|
705 | const canLeave = beforeLeaveHook ? await beforeLeaveHook() : true;
|
706 | if (canLeave === false || typeof canLeave === 'object') {
|
707 | return canLeave;
|
708 | }
|
709 | const toChain = routerPathToChain(to, routes);
|
710 | const beforeEnterHook = toChain && toChain[toChain.length - 1].beforeEnter;
|
711 | return beforeEnterHook ? beforeEnterHook() : true;
|
712 | }
|
713 | async writeNavState(node, chain, direction, path, redirectFrom, index = 0, animation) {
|
714 | if (this.busy) {
|
715 | console.warn('[ion-router] router is busy, transition was cancelled');
|
716 | return false;
|
717 | }
|
718 | this.busy = true;
|
719 |
|
720 | const routeEvent = this.routeChangeEvent(path, redirectFrom);
|
721 | if (routeEvent) {
|
722 | this.ionRouteWillChange.emit(routeEvent);
|
723 | }
|
724 | const changed = await writeNavState(node, chain, direction, index, false, animation);
|
725 | this.busy = false;
|
726 |
|
727 | if (routeEvent) {
|
728 | this.ionRouteDidChange.emit(routeEvent);
|
729 | }
|
730 | return changed;
|
731 | }
|
732 | setPath(path, direction, queryString) {
|
733 | this.state++;
|
734 | writePath(window.history, this.root, this.useHash, path, direction, this.state, queryString);
|
735 | }
|
736 | getPath() {
|
737 | return readPath(window.location, this.root, this.useHash);
|
738 | }
|
739 | routeChangeEvent(path, redirectFromPath) {
|
740 | const from = this.previousPath;
|
741 | const to = generatePath(path);
|
742 | this.previousPath = to;
|
743 | if (to === from) {
|
744 | return null;
|
745 | }
|
746 | const redirectedFrom = redirectFromPath ? generatePath(redirectFromPath) : null;
|
747 | return {
|
748 | from,
|
749 | redirectedFrom,
|
750 | to,
|
751 | };
|
752 | }
|
753 | get el() { return index.getElement(this); }
|
754 | };
|
755 |
|
756 | const routerLinkCss = ":host{--background:transparent;--color:var(--ion-color-primary, #3880ff);background:var(--background);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}a{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit}";
|
757 |
|
758 | const RouterLink = class {
|
759 | constructor(hostRef) {
|
760 | index.registerInstance(this, hostRef);
|
761 | |
762 |
|
763 |
|
764 |
|
765 | this.routerDirection = 'forward';
|
766 | this.onClick = (ev) => {
|
767 | theme.openURL(this.href, ev, this.routerDirection, this.routerAnimation);
|
768 | };
|
769 | }
|
770 | render() {
|
771 | const mode = ionicGlobal.getIonMode(this);
|
772 | const attrs = {
|
773 | href: this.href,
|
774 | rel: this.rel,
|
775 | target: this.target
|
776 | };
|
777 | return (index.h(index.Host, { onClick: this.onClick, class: theme.createColorClasses(this.color, {
|
778 | [mode]: true,
|
779 | 'ion-activatable': true
|
780 | }) }, index.h("a", Object.assign({}, attrs), index.h("slot", null))));
|
781 | }
|
782 | };
|
783 | RouterLink.style = routerLinkCss;
|
784 |
|
785 | exports.ion_route = Route;
|
786 | exports.ion_route_redirect = RouteRedirect;
|
787 | exports.ion_router = Router;
|
788 | exports.ion_router_link = RouterLink;
|