@merkur/plugin-router 0.27.0
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/LICENSE +7 -0
- package/README.md +56 -0
- package/jest.config.js +5 -0
- package/lib/RouterEvents.cjs +9 -0
- package/lib/RouterEvents.es5.js +1 -0
- package/lib/RouterEvents.es9.cjs +9 -0
- package/lib/RouterEvents.es9.mjs +4 -0
- package/lib/RouterEvents.js +9 -0
- package/lib/RouterEvents.mjs +5 -0
- package/lib/index.cjs +249 -0
- package/lib/index.es5.js +1 -0
- package/lib/index.es9.cjs +246 -0
- package/lib/index.es9.mjs +226 -0
- package/lib/index.js +249 -0
- package/lib/index.mjs +239 -0
- package/package.json +73 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { bindWidgetToFunctions, setDefaultValueForUndefined, hookMethod, isFunction } from '@merkur/core';
|
|
2
|
+
import UniversalRouter from 'universal-router';
|
|
3
|
+
import generateUrls from 'universal-router/generateUrls';
|
|
4
|
+
var RouterEvents = Object.freeze({
|
|
5
|
+
REDIRECT: '@merkur/plugin-router.redirect'
|
|
6
|
+
});
|
|
7
|
+
const DEV = 'development';
|
|
8
|
+
const ENV = typeof process !== 'undefined' && process && process.env ? process.env.NODE_ENV : DEV;
|
|
9
|
+
|
|
10
|
+
function createRouter(widget, routes, options) {
|
|
11
|
+
widget.$dependencies.router = new UniversalRouter(routes, options);
|
|
12
|
+
widget.$dependencies.link = generateUrls(widget.$dependencies.router);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function routerPlugin() {
|
|
16
|
+
return {
|
|
17
|
+
async setup(widget) {
|
|
18
|
+
widget = { ...routerAPI(),
|
|
19
|
+
...widget
|
|
20
|
+
};
|
|
21
|
+
widget.$in.router = {
|
|
22
|
+
route: null,
|
|
23
|
+
pathname: null,
|
|
24
|
+
isMounting: false,
|
|
25
|
+
isRouteActivated: false,
|
|
26
|
+
isBootstrapCalled: false
|
|
27
|
+
};
|
|
28
|
+
bindWidgetToFunctions(widget, widget.router);
|
|
29
|
+
return widget;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
async create(widget) {
|
|
33
|
+
if (ENV === DEV) {
|
|
34
|
+
if (!widget.$in.component) {
|
|
35
|
+
throw new Error('You must install missing plugin: npm i @merkur/plugin-component');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!widget.$in.eventEmitter) {
|
|
39
|
+
throw new Error('You must install missing plugin: npm i @merkur/plugin-event-emitter');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
widget.$in.component.lifeCycle = setDefaultValueForUndefined(widget.$in.component.lifeCycle, ['load'], () => {});
|
|
44
|
+
hookMethod(widget, '$in.component.lifeCycle.load', loadHook);
|
|
45
|
+
hookMethod(widget, 'bootstrap', bootstrapHook);
|
|
46
|
+
hookMethod(widget, 'mount', mountHook);
|
|
47
|
+
hookMethod(widget, 'unmount', unmountHook);
|
|
48
|
+
hookMethod(widget, 'update', updateHook);
|
|
49
|
+
return widget;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function routerAPI() {
|
|
56
|
+
return {
|
|
57
|
+
router: {
|
|
58
|
+
redirect(widget, url, data = {}) {
|
|
59
|
+
widget.emit(RouterEvents.REDIRECT, {
|
|
60
|
+
url,
|
|
61
|
+
...data
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
link(widget, routeName, data = {}) {
|
|
66
|
+
return widget.$dependencies.link(routeName, data);
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
getCurrentRoute(widget) {
|
|
70
|
+
return widget.$in.router.route;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function bootstrapHook(widget, originalBootstrap, ...rest) {
|
|
78
|
+
if (widget.$in.router.isBootstrapCalled) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
widget.$in.router.isBootstrapCalled = true;
|
|
83
|
+
return originalBootstrap(...rest);
|
|
84
|
+
} // hook Component
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async function loadHook(widget, originalLoad, ...rest) {
|
|
88
|
+
const plugin = widget.$in.router;
|
|
89
|
+
|
|
90
|
+
if (!plugin.isMounting && widget.props.pathname !== plugin.pathname) {
|
|
91
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
92
|
+
await setupRouterCycle(widget, ...rest);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!isFunction(plugin.route.load)) {
|
|
96
|
+
throw new Error('The load method is mandatory.');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const globalStatePromise = isFunction(originalLoad) ? originalLoad(widget, ...rest) : Promise.resolve({});
|
|
100
|
+
const routeStatePromise = plugin.route.load(widget, {
|
|
101
|
+
route: plugin.route,
|
|
102
|
+
args: rest,
|
|
103
|
+
globalState: globalStatePromise
|
|
104
|
+
});
|
|
105
|
+
const [globalState, routeState] = await Promise.all([globalStatePromise, routeStatePromise]);
|
|
106
|
+
return { ...globalState,
|
|
107
|
+
...routeState
|
|
108
|
+
};
|
|
109
|
+
} // hook Component
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async function mountHook(widget, originalMount, ...rest) {
|
|
113
|
+
await widget.bootstrap(...rest);
|
|
114
|
+
const plugin = widget.$in.router;
|
|
115
|
+
|
|
116
|
+
if (!plugin.route) {
|
|
117
|
+
await resolveRoute(widget);
|
|
118
|
+
plugin.isMounting = true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = await originalMount(...rest);
|
|
122
|
+
|
|
123
|
+
if (plugin.isMounting && isFunction(plugin.route.init)) {
|
|
124
|
+
await plugin.route.init(widget, {
|
|
125
|
+
route: plugin.route,
|
|
126
|
+
args: rest
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (isFunction(plugin.route.activate) && isClient() && !plugin.isRouteActivated) {
|
|
131
|
+
plugin.isRouteActivated = true;
|
|
132
|
+
plugin.route.activate(widget, {
|
|
133
|
+
route: plugin.route,
|
|
134
|
+
args: rest
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
plugin.isMounting = false;
|
|
139
|
+
return result;
|
|
140
|
+
} // hook Component
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async function updateHook(widget, originalUpdate, ...rest) {
|
|
144
|
+
const result = await originalUpdate(...rest);
|
|
145
|
+
const plugin = widget.$in.router;
|
|
146
|
+
|
|
147
|
+
if (isFunction(plugin.route.activate) && isClient() && !plugin.isRouteActivated) {
|
|
148
|
+
plugin.isRouteActivated = true;
|
|
149
|
+
plugin.route.activate(widget, {
|
|
150
|
+
route: plugin.route,
|
|
151
|
+
args: rest
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
} // hook Component
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
async function unmountHook(widget, originalUnmount, ...rest) {
|
|
160
|
+
const result = await originalUnmount(...rest);
|
|
161
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function resolveRoute(widget) {
|
|
166
|
+
if (ENV === DEV) {
|
|
167
|
+
if (!widget.props.pathname) {
|
|
168
|
+
throw new Error('The props pathname is not defined.');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!widget.$dependencies.router) {
|
|
172
|
+
throw new Error('You must add calling of createRouter(widget, routes, options) to widget.setup method.');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const route = await widget.$dependencies.router.resolve({
|
|
177
|
+
pathname: widget.props.pathname,
|
|
178
|
+
widget
|
|
179
|
+
});
|
|
180
|
+
widget.$in.router.route = route;
|
|
181
|
+
widget.$in.router.pathname = widget.props.pathname;
|
|
182
|
+
return route;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function setupRouterCycle(widget, ...rest) {
|
|
186
|
+
const route = await resolveRoute(widget);
|
|
187
|
+
|
|
188
|
+
if (isFunction(route.init)) {
|
|
189
|
+
await route.init(widget, {
|
|
190
|
+
route,
|
|
191
|
+
args: rest
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function tearDownRouterCycle(widget, ...rest) {
|
|
197
|
+
const plugin = widget.$in.router;
|
|
198
|
+
const {
|
|
199
|
+
route,
|
|
200
|
+
isRouteActivated
|
|
201
|
+
} = plugin;
|
|
202
|
+
|
|
203
|
+
if (route) {
|
|
204
|
+
if (isFunction(route.deactivate) && isRouteActivated === true) {
|
|
205
|
+
await route.deactivate(widget, {
|
|
206
|
+
route,
|
|
207
|
+
args: rest
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (isFunction(route.destroy)) {
|
|
212
|
+
await route.destroy(widget, {
|
|
213
|
+
route,
|
|
214
|
+
args: rest
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
plugin.isRouteActivated = false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function isClient() {
|
|
223
|
+
return typeof window !== 'undefined';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export { createRouter, routerPlugin };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var core = require('@merkur/core');
|
|
6
|
+
var UniversalRouter = require('universal-router');
|
|
7
|
+
var generateUrls = require('universal-router/generateUrls');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
10
|
+
|
|
11
|
+
var UniversalRouter__default = /*#__PURE__*/_interopDefaultLegacy(UniversalRouter);
|
|
12
|
+
var generateUrls__default = /*#__PURE__*/_interopDefaultLegacy(generateUrls);
|
|
13
|
+
|
|
14
|
+
var RouterEvents = Object.freeze({
|
|
15
|
+
REDIRECT: '@merkur/plugin-router.redirect',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const DEV = 'development';
|
|
19
|
+
const ENV =
|
|
20
|
+
typeof process !== 'undefined' && process && process.env
|
|
21
|
+
? process.env.NODE_ENV
|
|
22
|
+
: DEV;
|
|
23
|
+
|
|
24
|
+
function createRouter(widget, routes, options) {
|
|
25
|
+
widget.$dependencies.router = new UniversalRouter__default['default'](routes, options);
|
|
26
|
+
widget.$dependencies.link = generateUrls__default['default'](widget.$dependencies.router);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function routerPlugin() {
|
|
30
|
+
return {
|
|
31
|
+
async setup(widget) {
|
|
32
|
+
widget = {
|
|
33
|
+
...routerAPI(),
|
|
34
|
+
...widget,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
widget.$in.router = {
|
|
38
|
+
route: null,
|
|
39
|
+
pathname: null,
|
|
40
|
+
isMounting: false,
|
|
41
|
+
isRouteActivated: false,
|
|
42
|
+
isBootstrapCalled: false,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
core.bindWidgetToFunctions(widget, widget.router);
|
|
46
|
+
|
|
47
|
+
return widget;
|
|
48
|
+
},
|
|
49
|
+
async create(widget) {
|
|
50
|
+
if (ENV === DEV) {
|
|
51
|
+
if (!widget.$in.component) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
'You must install missing plugin: npm i @merkur/plugin-component'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!widget.$in.eventEmitter) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
'You must install missing plugin: npm i @merkur/plugin-event-emitter'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
widget.$in.component.lifeCycle = core.setDefaultValueForUndefined(
|
|
65
|
+
widget.$in.component.lifeCycle,
|
|
66
|
+
['load'],
|
|
67
|
+
() => {}
|
|
68
|
+
);
|
|
69
|
+
core.hookMethod(widget, '$in.component.lifeCycle.load', loadHook);
|
|
70
|
+
core.hookMethod(widget, 'bootstrap', bootstrapHook);
|
|
71
|
+
core.hookMethod(widget, 'mount', mountHook);
|
|
72
|
+
core.hookMethod(widget, 'unmount', unmountHook);
|
|
73
|
+
core.hookMethod(widget, 'update', updateHook);
|
|
74
|
+
|
|
75
|
+
return widget;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function routerAPI() {
|
|
81
|
+
return {
|
|
82
|
+
router: {
|
|
83
|
+
redirect(widget, url, data = {}) {
|
|
84
|
+
widget.emit(RouterEvents.REDIRECT, { url, ...data });
|
|
85
|
+
},
|
|
86
|
+
link(widget, routeName, data = {}) {
|
|
87
|
+
return widget.$dependencies.link(routeName, data);
|
|
88
|
+
},
|
|
89
|
+
getCurrentRoute(widget) {
|
|
90
|
+
return widget.$in.router.route;
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function bootstrapHook(widget, originalBootstrap, ...rest) {
|
|
97
|
+
if (widget.$in.router.isBootstrapCalled) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
widget.$in.router.isBootstrapCalled = true;
|
|
102
|
+
|
|
103
|
+
return originalBootstrap(...rest);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// hook Component
|
|
107
|
+
async function loadHook(widget, originalLoad, ...rest) {
|
|
108
|
+
const plugin = widget.$in.router;
|
|
109
|
+
|
|
110
|
+
if (!plugin.isMounting && widget.props.pathname !== plugin.pathname) {
|
|
111
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
112
|
+
|
|
113
|
+
await setupRouterCycle(widget, ...rest);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!core.isFunction(plugin.route.load)) {
|
|
117
|
+
throw new Error('The load method is mandatory.');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const globalStatePromise = core.isFunction(originalLoad)
|
|
121
|
+
? originalLoad(widget, ...rest)
|
|
122
|
+
: Promise.resolve({});
|
|
123
|
+
const routeStatePromise = plugin.route.load(widget, {
|
|
124
|
+
route: plugin.route,
|
|
125
|
+
args: rest,
|
|
126
|
+
globalState: globalStatePromise,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const [globalState, routeState] = await Promise.all([
|
|
130
|
+
globalStatePromise,
|
|
131
|
+
routeStatePromise,
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
return { ...globalState, ...routeState };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// hook Component
|
|
138
|
+
async function mountHook(widget, originalMount, ...rest) {
|
|
139
|
+
await widget.bootstrap(...rest);
|
|
140
|
+
|
|
141
|
+
const plugin = widget.$in.router;
|
|
142
|
+
if (!plugin.route) {
|
|
143
|
+
await resolveRoute(widget);
|
|
144
|
+
plugin.isMounting = true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const result = await originalMount(...rest);
|
|
148
|
+
|
|
149
|
+
if (plugin.isMounting && core.isFunction(plugin.route.init)) {
|
|
150
|
+
await plugin.route.init(widget, { route: plugin.route, args: rest });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
core.isFunction(plugin.route.activate) &&
|
|
155
|
+
isClient() &&
|
|
156
|
+
!plugin.isRouteActivated
|
|
157
|
+
) {
|
|
158
|
+
plugin.isRouteActivated = true;
|
|
159
|
+
plugin.route.activate(widget, { route: plugin.route, args: rest });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
plugin.isMounting = false;
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// hook Component
|
|
168
|
+
async function updateHook(widget, originalUpdate, ...rest) {
|
|
169
|
+
const result = await originalUpdate(...rest);
|
|
170
|
+
|
|
171
|
+
const plugin = widget.$in.router;
|
|
172
|
+
|
|
173
|
+
if (
|
|
174
|
+
core.isFunction(plugin.route.activate) &&
|
|
175
|
+
isClient() &&
|
|
176
|
+
!plugin.isRouteActivated
|
|
177
|
+
) {
|
|
178
|
+
plugin.isRouteActivated = true;
|
|
179
|
+
plugin.route.activate(widget, { route: plugin.route, args: rest });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// hook Component
|
|
186
|
+
async function unmountHook(widget, originalUnmount, ...rest) {
|
|
187
|
+
const result = await originalUnmount(...rest);
|
|
188
|
+
|
|
189
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
190
|
+
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function resolveRoute(widget) {
|
|
195
|
+
if (ENV === DEV) {
|
|
196
|
+
if (!widget.props.pathname) {
|
|
197
|
+
throw new Error('The props pathname is not defined.');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!widget.$dependencies.router) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
'You must add calling of createRouter(widget, routes, options) to widget.setup method.'
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const route = await widget.$dependencies.router.resolve({
|
|
208
|
+
pathname: widget.props.pathname,
|
|
209
|
+
widget,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
widget.$in.router.route = route;
|
|
213
|
+
widget.$in.router.pathname = widget.props.pathname;
|
|
214
|
+
|
|
215
|
+
return route;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function setupRouterCycle(widget, ...rest) {
|
|
219
|
+
const route = await resolveRoute(widget);
|
|
220
|
+
|
|
221
|
+
if (core.isFunction(route.init)) {
|
|
222
|
+
await route.init(widget, { route, args: rest });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function tearDownRouterCycle(widget, ...rest) {
|
|
227
|
+
const plugin = widget.$in.router;
|
|
228
|
+
|
|
229
|
+
const { route, isRouteActivated } = plugin;
|
|
230
|
+
|
|
231
|
+
if (route) {
|
|
232
|
+
if (core.isFunction(route.deactivate) && isRouteActivated === true) {
|
|
233
|
+
await route.deactivate(widget, { route, args: rest });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (core.isFunction(route.destroy)) {
|
|
237
|
+
await route.destroy(widget, { route, args: rest });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
plugin.isRouteActivated = false;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function isClient() {
|
|
245
|
+
return typeof window !== 'undefined';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
exports.createRouter = createRouter;
|
|
249
|
+
exports.routerPlugin = routerPlugin;
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { bindWidgetToFunctions, setDefaultValueForUndefined, hookMethod, isFunction } from '@merkur/core';
|
|
2
|
+
import UniversalRouter from 'universal-router';
|
|
3
|
+
import generateUrls from 'universal-router/generateUrls';
|
|
4
|
+
|
|
5
|
+
var RouterEvents = Object.freeze({
|
|
6
|
+
REDIRECT: '@merkur/plugin-router.redirect',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const DEV = 'development';
|
|
10
|
+
const ENV =
|
|
11
|
+
typeof process !== 'undefined' && process && process.env
|
|
12
|
+
? process.env.NODE_ENV
|
|
13
|
+
: DEV;
|
|
14
|
+
|
|
15
|
+
function createRouter(widget, routes, options) {
|
|
16
|
+
widget.$dependencies.router = new UniversalRouter(routes, options);
|
|
17
|
+
widget.$dependencies.link = generateUrls(widget.$dependencies.router);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function routerPlugin() {
|
|
21
|
+
return {
|
|
22
|
+
async setup(widget) {
|
|
23
|
+
widget = {
|
|
24
|
+
...routerAPI(),
|
|
25
|
+
...widget,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
widget.$in.router = {
|
|
29
|
+
route: null,
|
|
30
|
+
pathname: null,
|
|
31
|
+
isMounting: false,
|
|
32
|
+
isRouteActivated: false,
|
|
33
|
+
isBootstrapCalled: false,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
bindWidgetToFunctions(widget, widget.router);
|
|
37
|
+
|
|
38
|
+
return widget;
|
|
39
|
+
},
|
|
40
|
+
async create(widget) {
|
|
41
|
+
if (ENV === DEV) {
|
|
42
|
+
if (!widget.$in.component) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
'You must install missing plugin: npm i @merkur/plugin-component'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!widget.$in.eventEmitter) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
'You must install missing plugin: npm i @merkur/plugin-event-emitter'
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
widget.$in.component.lifeCycle = setDefaultValueForUndefined(
|
|
56
|
+
widget.$in.component.lifeCycle,
|
|
57
|
+
['load'],
|
|
58
|
+
() => {}
|
|
59
|
+
);
|
|
60
|
+
hookMethod(widget, '$in.component.lifeCycle.load', loadHook);
|
|
61
|
+
hookMethod(widget, 'bootstrap', bootstrapHook);
|
|
62
|
+
hookMethod(widget, 'mount', mountHook);
|
|
63
|
+
hookMethod(widget, 'unmount', unmountHook);
|
|
64
|
+
hookMethod(widget, 'update', updateHook);
|
|
65
|
+
|
|
66
|
+
return widget;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function routerAPI() {
|
|
72
|
+
return {
|
|
73
|
+
router: {
|
|
74
|
+
redirect(widget, url, data = {}) {
|
|
75
|
+
widget.emit(RouterEvents.REDIRECT, { url, ...data });
|
|
76
|
+
},
|
|
77
|
+
link(widget, routeName, data = {}) {
|
|
78
|
+
return widget.$dependencies.link(routeName, data);
|
|
79
|
+
},
|
|
80
|
+
getCurrentRoute(widget) {
|
|
81
|
+
return widget.$in.router.route;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function bootstrapHook(widget, originalBootstrap, ...rest) {
|
|
88
|
+
if (widget.$in.router.isBootstrapCalled) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
widget.$in.router.isBootstrapCalled = true;
|
|
93
|
+
|
|
94
|
+
return originalBootstrap(...rest);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// hook Component
|
|
98
|
+
async function loadHook(widget, originalLoad, ...rest) {
|
|
99
|
+
const plugin = widget.$in.router;
|
|
100
|
+
|
|
101
|
+
if (!plugin.isMounting && widget.props.pathname !== plugin.pathname) {
|
|
102
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
103
|
+
|
|
104
|
+
await setupRouterCycle(widget, ...rest);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!isFunction(plugin.route.load)) {
|
|
108
|
+
throw new Error('The load method is mandatory.');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const globalStatePromise = isFunction(originalLoad)
|
|
112
|
+
? originalLoad(widget, ...rest)
|
|
113
|
+
: Promise.resolve({});
|
|
114
|
+
const routeStatePromise = plugin.route.load(widget, {
|
|
115
|
+
route: plugin.route,
|
|
116
|
+
args: rest,
|
|
117
|
+
globalState: globalStatePromise,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const [globalState, routeState] = await Promise.all([
|
|
121
|
+
globalStatePromise,
|
|
122
|
+
routeStatePromise,
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
return { ...globalState, ...routeState };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// hook Component
|
|
129
|
+
async function mountHook(widget, originalMount, ...rest) {
|
|
130
|
+
await widget.bootstrap(...rest);
|
|
131
|
+
|
|
132
|
+
const plugin = widget.$in.router;
|
|
133
|
+
if (!plugin.route) {
|
|
134
|
+
await resolveRoute(widget);
|
|
135
|
+
plugin.isMounting = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const result = await originalMount(...rest);
|
|
139
|
+
|
|
140
|
+
if (plugin.isMounting && isFunction(plugin.route.init)) {
|
|
141
|
+
await plugin.route.init(widget, { route: plugin.route, args: rest });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
isFunction(plugin.route.activate) &&
|
|
146
|
+
isClient() &&
|
|
147
|
+
!plugin.isRouteActivated
|
|
148
|
+
) {
|
|
149
|
+
plugin.isRouteActivated = true;
|
|
150
|
+
plugin.route.activate(widget, { route: plugin.route, args: rest });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
plugin.isMounting = false;
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// hook Component
|
|
159
|
+
async function updateHook(widget, originalUpdate, ...rest) {
|
|
160
|
+
const result = await originalUpdate(...rest);
|
|
161
|
+
|
|
162
|
+
const plugin = widget.$in.router;
|
|
163
|
+
|
|
164
|
+
if (
|
|
165
|
+
isFunction(plugin.route.activate) &&
|
|
166
|
+
isClient() &&
|
|
167
|
+
!plugin.isRouteActivated
|
|
168
|
+
) {
|
|
169
|
+
plugin.isRouteActivated = true;
|
|
170
|
+
plugin.route.activate(widget, { route: plugin.route, args: rest });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// hook Component
|
|
177
|
+
async function unmountHook(widget, originalUnmount, ...rest) {
|
|
178
|
+
const result = await originalUnmount(...rest);
|
|
179
|
+
|
|
180
|
+
await tearDownRouterCycle(widget, ...rest);
|
|
181
|
+
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function resolveRoute(widget) {
|
|
186
|
+
if (ENV === DEV) {
|
|
187
|
+
if (!widget.props.pathname) {
|
|
188
|
+
throw new Error('The props pathname is not defined.');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!widget.$dependencies.router) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
'You must add calling of createRouter(widget, routes, options) to widget.setup method.'
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const route = await widget.$dependencies.router.resolve({
|
|
199
|
+
pathname: widget.props.pathname,
|
|
200
|
+
widget,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
widget.$in.router.route = route;
|
|
204
|
+
widget.$in.router.pathname = widget.props.pathname;
|
|
205
|
+
|
|
206
|
+
return route;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function setupRouterCycle(widget, ...rest) {
|
|
210
|
+
const route = await resolveRoute(widget);
|
|
211
|
+
|
|
212
|
+
if (isFunction(route.init)) {
|
|
213
|
+
await route.init(widget, { route, args: rest });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function tearDownRouterCycle(widget, ...rest) {
|
|
218
|
+
const plugin = widget.$in.router;
|
|
219
|
+
|
|
220
|
+
const { route, isRouteActivated } = plugin;
|
|
221
|
+
|
|
222
|
+
if (route) {
|
|
223
|
+
if (isFunction(route.deactivate) && isRouteActivated === true) {
|
|
224
|
+
await route.deactivate(widget, { route, args: rest });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (isFunction(route.destroy)) {
|
|
228
|
+
await route.destroy(widget, { route, args: rest });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
plugin.isRouteActivated = false;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isClient() {
|
|
236
|
+
return typeof window !== 'undefined';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export { createRouter, routerPlugin };
|