swup 4.3.3 → 4.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Swup.cjs +1 -1
- package/dist/Swup.cjs.map +1 -1
- package/dist/Swup.modern.js +1 -1
- package/dist/Swup.modern.js.map +1 -1
- package/dist/Swup.module.js +1 -1
- package/dist/Swup.module.js.map +1 -1
- package/dist/Swup.umd.js +1 -1
- package/dist/Swup.umd.js.map +1 -1
- package/dist/types/Swup.d.ts +1 -1
- package/dist/types/modules/Visit.d.ts +2 -0
- package/dist/types/modules/__test__/visit.test.d.ts +1 -0
- package/dist/types/modules/renderPage.d.ts +1 -2
- package/package.json +1 -1
- package/src/modules/Visit.ts +3 -0
- package/src/modules/__test__/visit.test.ts +92 -0
- package/src/modules/navigate.ts +28 -22
- package/src/modules/renderPage.ts +1 -7
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import Swup from '../../Swup.js';
|
|
3
|
+
import { Visit, createVisit } from '../Visit.js';
|
|
4
|
+
|
|
5
|
+
class SwupWithPublicVisitMethods extends Swup {
|
|
6
|
+
public createVisit = createVisit;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const swup = new SwupWithPublicVisitMethods();
|
|
10
|
+
let visit: Visit;
|
|
11
|
+
|
|
12
|
+
describe('Visit', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
visit = swup.createVisit({ to: '' });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('is an object', () => {
|
|
18
|
+
expect(visit).to.be.an('object');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('has an id', () => {
|
|
22
|
+
expect(visit.id).to.be.a('number');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('generates unique ids', () => {
|
|
26
|
+
let id = visit.id;
|
|
27
|
+
visit = swup.createVisit({ to: '' });
|
|
28
|
+
expect(visit.id).to.not.equal(id);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('has a from object with the current URL', () => {
|
|
32
|
+
expect(visit.from).to.be.an('object');
|
|
33
|
+
expect(visit.from.url).to.be.a('string');
|
|
34
|
+
visit = swup.createVisit({ to: '', from: '/from' });
|
|
35
|
+
expect(visit.from).toMatchObject({ url: '/from' });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('has a to object with the next URL', () => {
|
|
39
|
+
expect(visit.to).to.be.an('object');
|
|
40
|
+
expect(visit.to.url).to.be.a('string');
|
|
41
|
+
visit = swup.createVisit({ to: '/to' });
|
|
42
|
+
expect(visit.to).toMatchObject({ url: '/to' });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('has an animation object', () => {
|
|
46
|
+
expect(visit.animation).to.be.an('object');
|
|
47
|
+
expect(visit.animation).toMatchObject({
|
|
48
|
+
animate: true,
|
|
49
|
+
name: undefined,
|
|
50
|
+
scope: swup.options.animationScope,
|
|
51
|
+
selector: swup.options.animationSelector
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('has a container array', () => {
|
|
56
|
+
expect(visit.containers).to.be.an('array');
|
|
57
|
+
expect(visit.containers).toEqual(swup.options.containers);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('has a trigger object', () => {
|
|
61
|
+
expect(visit.trigger).to.be.an('object');
|
|
62
|
+
expect(visit.trigger).toMatchObject({
|
|
63
|
+
el: undefined,
|
|
64
|
+
event: undefined
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('has a cache object', () => {
|
|
69
|
+
expect(visit.cache).to.be.an('object');
|
|
70
|
+
expect(visit.cache).toEqual({
|
|
71
|
+
read: swup.options.cache,
|
|
72
|
+
write: swup.options.cache
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('has a history object', () => {
|
|
77
|
+
expect(visit.history).to.be.an('object');
|
|
78
|
+
expect(visit.history).toEqual({
|
|
79
|
+
action: 'push',
|
|
80
|
+
popstate: false,
|
|
81
|
+
direction: undefined
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('has a scroll object', () => {
|
|
86
|
+
expect(visit.scroll).to.be.an('object');
|
|
87
|
+
expect(visit.scroll).toEqual({
|
|
88
|
+
reset: true,
|
|
89
|
+
target: undefined
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
package/src/modules/navigate.ts
CHANGED
|
@@ -61,37 +61,41 @@ export function navigate(
|
|
|
61
61
|
export async function performNavigation(
|
|
62
62
|
this: Swup,
|
|
63
63
|
options: NavigationOptions & FetchOptions = {}
|
|
64
|
-
) {
|
|
65
|
-
|
|
64
|
+
): Promise<void> {
|
|
65
|
+
// Save this localy to a) allow ignoring the visit if a new one was started in the meantime
|
|
66
|
+
// and b) avoid unintended modifications to any newer visits
|
|
67
|
+
const visit = this.visit;
|
|
68
|
+
|
|
69
|
+
const { el } = visit.trigger;
|
|
66
70
|
options.referrer = options.referrer || this.currentPageUrl;
|
|
67
71
|
|
|
68
72
|
if (options.animate === false) {
|
|
69
|
-
|
|
73
|
+
visit.animation.animate = false;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
// Clean up old animation classes
|
|
73
|
-
if (!
|
|
77
|
+
if (!visit.animation.animate) {
|
|
74
78
|
this.classes.clear();
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
// Get history action from option or attribute on trigger element
|
|
78
82
|
const history = options.history || el?.getAttribute('data-swup-history') || undefined;
|
|
79
83
|
if (history && ['push', 'replace'].includes(history)) {
|
|
80
|
-
|
|
84
|
+
visit.history.action = history as HistoryAction;
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
// Get custom animation name from option or attribute on trigger element
|
|
84
88
|
const animation = options.animation || el?.getAttribute('data-swup-animation') || undefined;
|
|
85
89
|
if (animation) {
|
|
86
|
-
|
|
90
|
+
visit.animation.name = animation;
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
// Sanitize cache option
|
|
90
94
|
if (typeof options.cache === 'object') {
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
visit.cache.read = options.cache.read ?? visit.cache.read;
|
|
96
|
+
visit.cache.write = options.cache.write ?? visit.cache.write;
|
|
93
97
|
} else if (options.cache !== undefined) {
|
|
94
|
-
|
|
98
|
+
visit.cache = { read: !!options.cache, write: !!options.cache };
|
|
95
99
|
}
|
|
96
100
|
// Delete this so that window.fetch doesn't mis-interpret it
|
|
97
101
|
delete options.cache;
|
|
@@ -103,7 +107,7 @@ export async function performNavigation(
|
|
|
103
107
|
const pagePromise = this.hooks.call('page:load', { options }, async (visit, args) => {
|
|
104
108
|
// Read from cache
|
|
105
109
|
let cachedPage: PageData | undefined;
|
|
106
|
-
if (
|
|
110
|
+
if (visit.cache.read) {
|
|
107
111
|
cachedPage = this.cache.get(visit.to.url);
|
|
108
112
|
}
|
|
109
113
|
|
|
@@ -114,13 +118,10 @@ export async function performNavigation(
|
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
// Create/update history record if this is not a popstate call or leads to the same URL
|
|
117
|
-
if (!
|
|
121
|
+
if (!visit.history.popstate) {
|
|
118
122
|
// Add the hash directly from the trigger element
|
|
119
|
-
const newUrl =
|
|
120
|
-
if (
|
|
121
|
-
this.visit.history.action === 'replace' ||
|
|
122
|
-
this.visit.to.url === this.currentPageUrl
|
|
123
|
-
) {
|
|
123
|
+
const newUrl = visit.to.url + visit.to.hash;
|
|
124
|
+
if (visit.history.action === 'replace' || visit.to.url === this.currentPageUrl) {
|
|
124
125
|
updateHistoryRecord(newUrl);
|
|
125
126
|
} else {
|
|
126
127
|
this.currentHistoryIndex++;
|
|
@@ -131,17 +132,22 @@ export async function performNavigation(
|
|
|
131
132
|
this.currentPageUrl = getCurrentUrl();
|
|
132
133
|
|
|
133
134
|
// Wait for page before starting to animate out?
|
|
134
|
-
if (
|
|
135
|
+
if (visit.animation.wait) {
|
|
135
136
|
const { html } = await pagePromise;
|
|
136
|
-
|
|
137
|
+
visit.to.html = html;
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
// Wait for page to load and leave animation to finish
|
|
140
141
|
const animationPromise = this.animatePageOut();
|
|
141
142
|
const [page] = await Promise.all([pagePromise, animationPromise]);
|
|
142
143
|
|
|
144
|
+
// Abort if another visit was started in the meantime
|
|
145
|
+
if (visit.id !== this.visit.id) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
143
149
|
// Render page: replace content and scroll to top/fragment
|
|
144
|
-
await this.renderPage(
|
|
150
|
+
await this.renderPage(page);
|
|
145
151
|
|
|
146
152
|
// Wait for enter animation
|
|
147
153
|
await this.animatePageIn();
|
|
@@ -150,8 +156,8 @@ export async function performNavigation(
|
|
|
150
156
|
await this.hooks.call('visit:end', undefined, () => this.classes.clear());
|
|
151
157
|
|
|
152
158
|
// Reset visit info after finish?
|
|
153
|
-
// if (
|
|
154
|
-
// this.createVisit({ to: undefined });
|
|
159
|
+
// if (visit.to && this.isSameResolvedUrl(visit.to.url, requestedUrl)) {
|
|
160
|
+
// this.visit = this.createVisit({ to: undefined });
|
|
155
161
|
// }
|
|
156
162
|
} catch (error: unknown) {
|
|
157
163
|
// Return early if error is undefined (probably aborted preload request)
|
|
@@ -164,7 +170,7 @@ export async function performNavigation(
|
|
|
164
170
|
|
|
165
171
|
// Rewrite `skipPopStateHandling` to redirect manually when `history.go` is processed
|
|
166
172
|
this.options.skipPopStateHandling = () => {
|
|
167
|
-
window.location.href =
|
|
173
|
+
window.location.href = visit.to.url + visit.to.hash;
|
|
168
174
|
return true;
|
|
169
175
|
};
|
|
170
176
|
|
|
@@ -4,18 +4,12 @@ import { PageData } from './fetchPage.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Render the next page: replace the content and update scroll position.
|
|
7
|
-
* @returns Promise<void>
|
|
8
7
|
*/
|
|
9
|
-
export const renderPage = async function (this: Swup,
|
|
8
|
+
export const renderPage = async function (this: Swup, page: PageData): Promise<void> {
|
|
10
9
|
const { url, html } = page;
|
|
11
10
|
|
|
12
11
|
this.classes.remove('is-leaving');
|
|
13
12
|
|
|
14
|
-
// do nothing if another page was requested in the meantime
|
|
15
|
-
if (!this.isSameResolvedUrl(getCurrentUrl(), requestedUrl)) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
// update state if the url was redirected
|
|
20
14
|
if (!this.isSameResolvedUrl(getCurrentUrl(), url)) {
|
|
21
15
|
updateHistoryRecord(url);
|