@keenmate/svelte-spa-router 1.0.1 → 1.0.2
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/.editorconfig +18 -0
- package/Router.d.ts +4 -0
- package/Router.svelte +90 -73
- package/active.js +17 -15
- package/constants.js +1 -1
- package/nightwatch.conf.cjs +39 -39
- package/package.json +1 -1
- package/wrap.js +6 -6
package/.editorconfig
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*.{cs,js,scss,css,cshtml,json,svelte,vue}]
|
|
4
|
+
indent_style = tab
|
|
5
|
+
indent_size = 2
|
|
6
|
+
trim_trailing_whitespace = true
|
|
7
|
+
charset = utf-8
|
|
8
|
+
ij_javascript_use_semicolon_after_statement = false
|
|
9
|
+
ij_typescript_use_semicolon_after_statement = false
|
|
10
|
+
|
|
11
|
+
[*.{xaml,cshtml,html,xml}]
|
|
12
|
+
indent_style = tab
|
|
13
|
+
indent_size = 2
|
|
14
|
+
trim_trailing_whitespace = true
|
|
15
|
+
charset = utf-8
|
|
16
|
+
|
|
17
|
+
[*.cs]
|
|
18
|
+
csharp_new_line_before_open_brace = all
|
package/Router.d.ts
CHANGED
|
@@ -97,6 +97,10 @@ export type LinkActionOpts = {
|
|
|
97
97
|
href?: string
|
|
98
98
|
/** If true, link is disabled */
|
|
99
99
|
disabled?: boolean
|
|
100
|
+
/**
|
|
101
|
+
* If true, link will replace instead of push new history entry
|
|
102
|
+
*/
|
|
103
|
+
replace?: boolean
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
/** Type for the update function of the link action */
|
package/Router.svelte
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script context="module">
|
|
2
|
-
import {derived, get, readable, writable} from
|
|
3
|
-
import {tick} from
|
|
4
|
-
import {SvelteSPARouterNavigationEvent} from
|
|
5
|
-
import {joinPaths} from
|
|
2
|
+
import {derived, get, readable, writable} from 'svelte/store'
|
|
3
|
+
import {tick} from 'svelte'
|
|
4
|
+
import {SvelteSPARouterNavigationEvent} from './constants.js'
|
|
5
|
+
import {joinPaths} from './helpers/url-helpers.js'
|
|
6
6
|
|
|
7
7
|
export const HashRoutingEnabled = writable(true)
|
|
8
|
-
export const BasePath = writable(
|
|
8
|
+
export const BasePath = writable('/')
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns the current location from the hash.
|
|
@@ -15,26 +15,28 @@
|
|
|
15
15
|
*/
|
|
16
16
|
function getLocation() {
|
|
17
17
|
const hashRoutingEnabled = get(HashRoutingEnabled)
|
|
18
|
-
const basePath
|
|
18
|
+
const basePath = get(BasePath)
|
|
19
19
|
let location
|
|
20
20
|
|
|
21
21
|
if (hashRoutingEnabled) {
|
|
22
|
-
const hashPosition = window.location.href.indexOf(
|
|
22
|
+
const hashPosition = window.location.href.indexOf('#/')
|
|
23
23
|
location = (hashPosition > -1) ?
|
|
24
24
|
window.location.href.substr(hashPosition + 1) :
|
|
25
|
-
|
|
26
|
-
}
|
|
25
|
+
'/'
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
27
28
|
const startsWithPrefix = window.location.pathname.startsWith(basePath)
|
|
28
29
|
if (!hashRoutingEnabled && !startsWithPrefix) {
|
|
29
|
-
throw new Error(`Hash routing disabled and location: "${window.location.href}" does not start with expected base path: "${get(
|
|
30
|
+
throw new Error(`Hash routing disabled and location: "${window.location.href}" does not start with expected base path: "${get(
|
|
31
|
+
BasePath)}"`)
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
location =
|
|
34
|
+
location = '/' + window.location.pathname.substring(basePath.length)
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
// Check if there's a querystring
|
|
36
|
-
const qsPosition = location.indexOf(
|
|
37
|
-
let querystring =
|
|
38
|
+
const qsPosition = location.indexOf('?')
|
|
39
|
+
let querystring = ''
|
|
38
40
|
if (qsPosition > -1) {
|
|
39
41
|
querystring = location.substr(qsPosition + 1)
|
|
40
42
|
location = location.substr(0, qsPosition)
|
|
@@ -53,11 +55,11 @@
|
|
|
53
55
|
set(getLocation())
|
|
54
56
|
|
|
55
57
|
const eventName = get(HashRoutingEnabled) ?
|
|
56
|
-
|
|
58
|
+
'hashchange' :
|
|
57
59
|
SvelteSPARouterNavigationEvent
|
|
58
|
-
console.log(
|
|
60
|
+
console.log('Setting loc')
|
|
59
61
|
const update = () => {
|
|
60
|
-
console.log(
|
|
62
|
+
console.log('Updating location', getLocation())
|
|
61
63
|
set(getLocation())
|
|
62
64
|
}
|
|
63
65
|
window.addEventListener(eventName, update, false)
|
|
@@ -125,15 +127,16 @@
|
|
|
125
127
|
|
|
126
128
|
async function jediForcePush(location, shouldReplace = false) {
|
|
127
129
|
const hashRoutingEnabled = get(HashRoutingEnabled)
|
|
128
|
-
const basePath
|
|
130
|
+
const basePath = get(BasePath)
|
|
129
131
|
|
|
130
132
|
if (hashRoutingEnabled) {
|
|
131
133
|
if (!location || location.length < 1 || !/^(\/|#\/)/.test(location)) {
|
|
132
|
-
throw Error(
|
|
134
|
+
throw Error('Invalid parameter location')
|
|
133
135
|
}
|
|
134
|
-
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
135
138
|
if (!location || location.length < 1 || !/^\//.test(location)) {
|
|
136
|
-
throw Error(
|
|
139
|
+
throw Error('Invalid parameter location')
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
|
|
@@ -155,17 +158,19 @@
|
|
|
155
158
|
doNavigate(newHistoryState, undefined)
|
|
156
159
|
|
|
157
160
|
if (!shouldReplace) {
|
|
158
|
-
window.location.hash = (location.charAt(0) ===
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
+
window.location.hash = (location.charAt(0) === '#' ? '' : '#') + location
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
window.dispatchEvent(new Event('hashchange'))
|
|
161
165
|
}
|
|
162
|
-
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
163
168
|
if (!location.startsWith(basePath)) {
|
|
164
169
|
location = joinPaths(basePath, location)
|
|
165
170
|
}
|
|
166
171
|
|
|
167
172
|
console.log(
|
|
168
|
-
|
|
173
|
+
'Before navigate',
|
|
169
174
|
window.history,
|
|
170
175
|
window.history.pushState,
|
|
171
176
|
doNavigate,
|
|
@@ -185,7 +190,7 @@
|
|
|
185
190
|
* @typedef {Object} LinkActionOpts
|
|
186
191
|
* @property {string} href - A string to use in place of the link's href attribute. Using this allows for updating link's targets reactively.
|
|
187
192
|
* @property {boolean} disabled - If true, link is disabled
|
|
188
|
-
* @property {boolean}
|
|
193
|
+
* @property {boolean} replace - If true, link will replace instead of push new history entry
|
|
189
194
|
*/
|
|
190
195
|
|
|
191
196
|
/**
|
|
@@ -204,20 +209,20 @@
|
|
|
204
209
|
opts = linkOpts(opts)
|
|
205
210
|
|
|
206
211
|
// Only apply to <a> tags
|
|
207
|
-
if (!node || !node.tagName || node.tagName.toLowerCase() !=
|
|
208
|
-
throw Error(
|
|
212
|
+
if (!node || !node.tagName || node.tagName.toLowerCase() != 'a') {
|
|
213
|
+
throw Error('Action "link" can only be used with <a> tags')
|
|
209
214
|
}
|
|
210
215
|
|
|
211
216
|
updateLink(node, opts)
|
|
212
217
|
|
|
213
218
|
if (!get(HashRoutingEnabled)) {
|
|
214
|
-
node.addEventListener(
|
|
219
|
+
node.addEventListener('click', ev => {
|
|
215
220
|
ev.stopImmediatePropagation()
|
|
216
221
|
ev.preventDefault()
|
|
217
222
|
|
|
218
|
-
const shouldReplace = typeof opts !==
|
|
223
|
+
const shouldReplace = typeof opts !== 'string' && opts.shouldReplace
|
|
219
224
|
|
|
220
|
-
jediForcePush(node.getAttribute(
|
|
225
|
+
jediForcePush(node.getAttribute('href'), shouldReplace)
|
|
221
226
|
window.dispatchEvent(new Event(SvelteSPARouterNavigationEvent))
|
|
222
227
|
}, {capture: true})
|
|
223
228
|
}
|
|
@@ -239,7 +244,8 @@
|
|
|
239
244
|
// If this exists, then this is a back navigation: restore the scroll position
|
|
240
245
|
if (state) {
|
|
241
246
|
window.scrollTo(state.__svelte_spa_router_scrollX, state.__svelte_spa_router_scrollY)
|
|
242
|
-
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
243
249
|
// Otherwise this is a forward navigation: scroll to top
|
|
244
250
|
window.scrollTo(0, 0)
|
|
245
251
|
}
|
|
@@ -249,38 +255,41 @@
|
|
|
249
255
|
function updateLink(node, opts) {
|
|
250
256
|
const basePath = get(BasePath)
|
|
251
257
|
|
|
252
|
-
let href = opts.href || node.getAttribute(
|
|
258
|
+
let href = opts.href || node.getAttribute('href')
|
|
253
259
|
|
|
254
260
|
if (get(HashRoutingEnabled)) {
|
|
255
|
-
if (href && href.charAt(0) ==
|
|
261
|
+
if (href && href.charAt(0) == '/') {
|
|
256
262
|
// Add # to the href attribute
|
|
257
|
-
href =
|
|
258
|
-
} else if (!href || href.length < 2 || href.slice(0, 2) != "#/") {
|
|
259
|
-
throw Error("Invalid value for \"href\" attribute: " + href)
|
|
263
|
+
href = '#' + href
|
|
260
264
|
}
|
|
261
|
-
|
|
265
|
+
else if (!href || href.length < 2 || href.slice(0, 2) != '#/') {
|
|
266
|
+
throw Error('Invalid value for "href" attribute: ' + href)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
262
270
|
if (href && !href.startsWith(basePath)) {
|
|
263
271
|
href = joinPaths(basePath, href)
|
|
264
272
|
}
|
|
265
273
|
}
|
|
266
274
|
|
|
267
|
-
node.setAttribute(
|
|
268
|
-
node.addEventListener(
|
|
275
|
+
node.setAttribute('href', href)
|
|
276
|
+
node.addEventListener('click', (event) => {
|
|
269
277
|
// Prevent default anchor onclick behaviour
|
|
270
278
|
event.preventDefault()
|
|
271
279
|
if (!opts.disabled) {
|
|
272
|
-
scrollstateHistoryHandler(event.currentTarget.getAttribute(
|
|
280
|
+
scrollstateHistoryHandler(event.currentTarget.getAttribute('href'))
|
|
273
281
|
}
|
|
274
282
|
})
|
|
275
283
|
}
|
|
276
284
|
|
|
277
285
|
// Internal function that ensures the argument of the link action is always an object
|
|
278
286
|
function linkOpts(val) {
|
|
279
|
-
if (val && typeof val ==
|
|
287
|
+
if (val && typeof val == 'string') {
|
|
280
288
|
return {
|
|
281
289
|
href: val
|
|
282
290
|
}
|
|
283
|
-
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
284
293
|
return val || {}
|
|
285
294
|
}
|
|
286
295
|
}
|
|
@@ -319,8 +328,8 @@
|
|
|
319
328
|
{/if}
|
|
320
329
|
|
|
321
330
|
<script>
|
|
322
|
-
import {onDestroy, createEventDispatcher, afterUpdate} from
|
|
323
|
-
import {parse} from
|
|
331
|
+
import {onDestroy, createEventDispatcher, afterUpdate} from 'svelte'
|
|
332
|
+
import {parse} from 'regexparam'
|
|
324
333
|
|
|
325
334
|
/**
|
|
326
335
|
* Dictionary of all routes, in the format `'/path': component`.
|
|
@@ -342,7 +351,7 @@
|
|
|
342
351
|
/**
|
|
343
352
|
* Optional prefix for the routes in this router. This is useful for example in the case of nested routers.
|
|
344
353
|
*/
|
|
345
|
-
export let prefix =
|
|
354
|
+
export let prefix = ''
|
|
346
355
|
|
|
347
356
|
/**
|
|
348
357
|
* If set to true, the router will restore scroll positions on back navigation
|
|
@@ -361,16 +370,16 @@
|
|
|
361
370
|
* @param {SvelteComponent|WrappedComponent} component - Svelte component for the route, optionally wrapped
|
|
362
371
|
*/
|
|
363
372
|
constructor(path, component) {
|
|
364
|
-
if (!component || (typeof component !=
|
|
365
|
-
throw Error(
|
|
373
|
+
if (!component || (typeof component != 'function' && (typeof component != 'object' || component._sveltesparouter !== true))) {
|
|
374
|
+
throw Error('Invalid component object')
|
|
366
375
|
}
|
|
367
376
|
|
|
368
377
|
// Path must be a regular or expression, or a string starting with '/' or '*'
|
|
369
378
|
if (!path ||
|
|
370
|
-
(typeof path ==
|
|
371
|
-
(typeof path ==
|
|
379
|
+
(typeof path == 'string' && (path.length < 1 || (path.charAt(0) != '/' && path.charAt(0) != '*'))) ||
|
|
380
|
+
(typeof path == 'object' && !(path instanceof RegExp))
|
|
372
381
|
) {
|
|
373
|
-
throw Error(
|
|
382
|
+
throw Error('Invalid value for "path" argument - strings must start with / or *')
|
|
374
383
|
}
|
|
375
384
|
|
|
376
385
|
const {pattern, keys} = parse(path)
|
|
@@ -378,12 +387,13 @@
|
|
|
378
387
|
this.path = path
|
|
379
388
|
|
|
380
389
|
// Check if the component is wrapped and we have conditions
|
|
381
|
-
if (typeof component ==
|
|
390
|
+
if (typeof component == 'object' && component._sveltesparouter === true) {
|
|
382
391
|
this.component = component.component
|
|
383
392
|
this.conditions = component.conditions || []
|
|
384
393
|
this.userData = component.userData
|
|
385
394
|
this.props = component.props || {}
|
|
386
|
-
}
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
387
397
|
// Convert the component to a function that returns a Promise, to normalize it
|
|
388
398
|
this.component = () => Promise.resolve(component)
|
|
389
399
|
this.conditions = []
|
|
@@ -406,17 +416,20 @@
|
|
|
406
416
|
// If there's a prefix, check if it matches the start of the path.
|
|
407
417
|
// If not, bail early, else remove it before we run the matching.
|
|
408
418
|
if (prefix) {
|
|
409
|
-
if (typeof prefix ==
|
|
419
|
+
if (typeof prefix == 'string') {
|
|
410
420
|
if (path.startsWith(prefix)) {
|
|
411
|
-
path = path.substr(prefix.length) ||
|
|
412
|
-
}
|
|
421
|
+
path = path.substr(prefix.length) || '/'
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
413
424
|
return null
|
|
414
425
|
}
|
|
415
|
-
}
|
|
426
|
+
}
|
|
427
|
+
else if (prefix instanceof RegExp) {
|
|
416
428
|
const match = path.match(prefix)
|
|
417
429
|
if (match && match[0]) {
|
|
418
|
-
path = path.substr(match[0].length) ||
|
|
419
|
-
}
|
|
430
|
+
path = path.substr(match[0].length) || '/'
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
420
433
|
return null
|
|
421
434
|
}
|
|
422
435
|
}
|
|
@@ -438,7 +451,7 @@
|
|
|
438
451
|
while (i < this._keys.length) {
|
|
439
452
|
// In the match parameters, URL-decode all values
|
|
440
453
|
try {
|
|
441
|
-
out[this._keys[i]] = decodeURIComponent(matches[i + 1] ||
|
|
454
|
+
out[this._keys[i]] = decodeURIComponent(matches[i + 1] || '') || null
|
|
442
455
|
} catch (e) {
|
|
443
456
|
out[this._keys[i]] = null
|
|
444
457
|
}
|
|
@@ -482,7 +495,8 @@
|
|
|
482
495
|
routes.forEach((route, path) => {
|
|
483
496
|
routesList.push(new RouteItem(path, route))
|
|
484
497
|
})
|
|
485
|
-
}
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
486
500
|
// We have an object, so iterate on its own properties
|
|
487
501
|
Object.keys(routes).forEach((path) => {
|
|
488
502
|
routesList.push(new RouteItem(path, routes[path]))
|
|
@@ -508,7 +522,7 @@
|
|
|
508
522
|
let previousScrollState = null
|
|
509
523
|
|
|
510
524
|
// Update history.scrollRestoration depending on restoreScrollState
|
|
511
|
-
$: history.scrollRestoration = restoreScrollState ?
|
|
525
|
+
$: history.scrollRestoration = restoreScrollState ? 'manual' : 'auto'
|
|
512
526
|
let popStateChanged = null
|
|
513
527
|
if (restoreScrollState) {
|
|
514
528
|
popStateChanged = (event) => {
|
|
@@ -517,12 +531,13 @@
|
|
|
517
531
|
// navigation)
|
|
518
532
|
if (event.state && (event.state.__svelte_spa_router_scrollY || event.state.__svelte_spa_router_scrollX)) {
|
|
519
533
|
previousScrollState = event.state
|
|
520
|
-
}
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
521
536
|
previousScrollState = null
|
|
522
537
|
}
|
|
523
538
|
}
|
|
524
539
|
// This is removed in the destroy() invocation below
|
|
525
|
-
window.addEventListener(
|
|
540
|
+
window.addEventListener('popstate', popStateChanged)
|
|
526
541
|
|
|
527
542
|
afterUpdate(() => {
|
|
528
543
|
restoreScroll(previousScrollState)
|
|
@@ -555,7 +570,7 @@
|
|
|
555
570
|
location: newLoc.location,
|
|
556
571
|
querystring: newLoc.querystring,
|
|
557
572
|
userData: routesList[i].userData,
|
|
558
|
-
params: (match && typeof match ==
|
|
573
|
+
params: (match && typeof match == 'object' && Object.keys(match).length) ? match : null
|
|
559
574
|
}
|
|
560
575
|
|
|
561
576
|
// Check if the route can be loaded - if all conditions succeed
|
|
@@ -564,13 +579,13 @@
|
|
|
564
579
|
component = null
|
|
565
580
|
componentObj = null
|
|
566
581
|
// Trigger an event to notify the user, then exit
|
|
567
|
-
dispatchNextTick(
|
|
582
|
+
dispatchNextTick('conditionsFailed', detail)
|
|
568
583
|
return
|
|
569
584
|
}
|
|
570
585
|
|
|
571
586
|
// Trigger an event to alert that we're loading the route
|
|
572
587
|
// We need to clone the object on every event invocation so we don't risk the object to be modified in the next tick
|
|
573
|
-
dispatchNextTick(
|
|
588
|
+
dispatchNextTick('routeLoading', Object.assign({}, detail))
|
|
574
589
|
|
|
575
590
|
// If there's a component to show while we're loading the route, display it
|
|
576
591
|
const obj = routesList[i].component
|
|
@@ -584,12 +599,13 @@
|
|
|
584
599
|
|
|
585
600
|
// Trigger the routeLoaded event for the loading component
|
|
586
601
|
// Create a copy of detail so we don't modify the object for the dynamic route (and the dynamic route doesn't modify our object too)
|
|
587
|
-
dispatchNextTick(
|
|
602
|
+
dispatchNextTick('routeLoaded', Object.assign({}, detail, {
|
|
588
603
|
component: component,
|
|
589
604
|
name: component.name,
|
|
590
605
|
params: componentParams
|
|
591
606
|
}))
|
|
592
|
-
}
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
593
609
|
component = null
|
|
594
610
|
componentObj = null
|
|
595
611
|
}
|
|
@@ -610,9 +626,10 @@
|
|
|
610
626
|
|
|
611
627
|
// Set componentParams only if we have a match, to avoid a warning similar to `<Component> was created with unknown prop 'params'`
|
|
612
628
|
// Of course, this assumes that developers always add a "params" prop when they are expecting parameters
|
|
613
|
-
if (match && typeof match ==
|
|
629
|
+
if (match && typeof match == 'object' && Object.keys(match).length) {
|
|
614
630
|
componentParams = match
|
|
615
|
-
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
616
633
|
componentParams = null
|
|
617
634
|
}
|
|
618
635
|
|
|
@@ -621,7 +638,7 @@
|
|
|
621
638
|
|
|
622
639
|
// Dispatch the routeLoaded event then exit
|
|
623
640
|
// We need to clone the object on every event invocation so we don't risk the object to be modified in the next tick
|
|
624
|
-
dispatchNextTick(
|
|
641
|
+
dispatchNextTick('routeLoaded', Object.assign({}, detail, {
|
|
625
642
|
component: component,
|
|
626
643
|
name: component.name,
|
|
627
644
|
params: componentParams
|
|
@@ -639,6 +656,6 @@
|
|
|
639
656
|
|
|
640
657
|
onDestroy(() => {
|
|
641
658
|
unsubscribeLoc()
|
|
642
|
-
popStateChanged && window.removeEventListener(
|
|
659
|
+
popStateChanged && window.removeEventListener('popstate', popStateChanged)
|
|
643
660
|
})
|
|
644
661
|
</script>
|
package/active.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {parse} from
|
|
2
|
-
import {BasePath, HashRoutingEnabled, loc} from
|
|
3
|
-
import {get} from
|
|
1
|
+
import {parse} from 'regexparam'
|
|
2
|
+
import {BasePath, HashRoutingEnabled, loc} from './Router.svelte'
|
|
3
|
+
import {get} from 'svelte/store'
|
|
4
4
|
|
|
5
5
|
// List of nodes to update
|
|
6
6
|
const nodes = []
|
|
@@ -16,7 +16,7 @@ function checkActive(el) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function toggleClasses(el, className, shouldAdd) {
|
|
19
|
-
(className ||
|
|
19
|
+
(className || '').split(' ').forEach((cls) => {
|
|
20
20
|
if (!cls) {
|
|
21
21
|
return
|
|
22
22
|
}
|
|
@@ -33,7 +33,7 @@ function toggleClasses(el, className, shouldAdd) {
|
|
|
33
33
|
// Listen to changes in the location
|
|
34
34
|
loc.subscribe((value) => {
|
|
35
35
|
// Update the location
|
|
36
|
-
location = value.location + (value.querystring ?
|
|
36
|
+
location = value.location + (value.querystring ? '?' + value.querystring : '')
|
|
37
37
|
|
|
38
38
|
// Update all nodes
|
|
39
39
|
nodes.map(checkActive)
|
|
@@ -56,25 +56,27 @@ export default function active(node, opts) {
|
|
|
56
56
|
const basePath = get(BasePath)
|
|
57
57
|
|
|
58
58
|
// Check options
|
|
59
|
-
if (opts && (typeof opts ==
|
|
59
|
+
if (opts && (typeof opts == 'string' || (typeof opts == 'object' && opts instanceof RegExp))) {
|
|
60
60
|
// Interpret strings and regular expressions as opts.path
|
|
61
61
|
opts = {
|
|
62
62
|
path: opts
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
65
66
|
// Ensure opts is a dictionary
|
|
66
67
|
opts = opts || {}
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
// Path defaults to link target
|
|
70
|
-
if (!opts.path && node.hasAttribute(
|
|
71
|
-
opts.path = node.getAttribute(
|
|
71
|
+
if (!opts.path && node.hasAttribute('href')) {
|
|
72
|
+
opts.path = node.getAttribute('href')
|
|
72
73
|
|
|
73
74
|
if (get(HashRoutingEnabled)) {
|
|
74
|
-
if (opts.path && opts.path.length > 1 && opts.path.charAt(0) ==
|
|
75
|
+
if (opts.path && opts.path.length > 1 && opts.path.charAt(0) == '#') {
|
|
75
76
|
opts.path = opts.path.substring(1)
|
|
76
77
|
}
|
|
77
|
-
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
78
80
|
if (opts.path.startsWith(basePath)) {
|
|
79
81
|
opts.path = opts.path.substring(basePath.length)
|
|
80
82
|
}
|
|
@@ -83,18 +85,18 @@ export default function active(node, opts) {
|
|
|
83
85
|
|
|
84
86
|
// Default class name
|
|
85
87
|
if (!opts.className) {
|
|
86
|
-
opts.className =
|
|
88
|
+
opts.className = 'active'
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
// If path is a string, it must start with '/' or '*'
|
|
90
92
|
if (!opts.path ||
|
|
91
|
-
typeof opts.path ==
|
|
93
|
+
typeof opts.path == 'string' && (opts.path.length < 1 || (opts.path.charAt(0) != '/' && opts.path.charAt(0) != '*'))
|
|
92
94
|
) {
|
|
93
|
-
throw Error(
|
|
95
|
+
throw Error('Invalid value for "path" argument')
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
// If path is not a regular expression already, make it
|
|
97
|
-
const {pattern} = typeof opts.path ==
|
|
99
|
+
const {pattern} = typeof opts.path == 'string' ?
|
|
98
100
|
parse(opts.path) :
|
|
99
101
|
{pattern: opts.path}
|
|
100
102
|
|
package/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SvelteSPARouterNavigationEvent =
|
|
1
|
+
export const SvelteSPARouterNavigationEvent = 'popstate'
|
package/nightwatch.conf.cjs
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
// Selenium configuration
|
|
2
|
-
const seleniumHost = process.env.SELENIUM_HOST ||
|
|
3
|
-
const seleniumPort = parseInt(process.env.SELENIUM_PORT ||
|
|
2
|
+
const seleniumHost = process.env.SELENIUM_HOST || '127.0.0.1'
|
|
3
|
+
const seleniumPort = parseInt(process.env.SELENIUM_PORT || '4444', 10)
|
|
4
4
|
|
|
5
5
|
// Launch URL - where the server is
|
|
6
|
-
const launchUrl = process.env.LAUNCH_URL ||
|
|
6
|
+
const launchUrl = process.env.LAUNCH_URL || 'http://localhost:5050'
|
|
7
7
|
|
|
8
8
|
// Increase max listeners to avoid a warning
|
|
9
|
-
require(
|
|
9
|
+
require('events').EventEmitter.defaultMaxListeners = 100
|
|
10
10
|
|
|
11
11
|
module.exports = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
src_folders: [
|
|
13
|
+
'test/cases/'
|
|
14
|
+
],
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
output_folder: 'result',
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
test_settings: {
|
|
27
|
-
default: {
|
|
28
|
-
launch_url: launchUrl
|
|
18
|
+
test_runner: {
|
|
19
|
+
type: 'mocha',
|
|
20
|
+
options: {
|
|
21
|
+
ui: 'bdd',
|
|
22
|
+
reporter: 'list'
|
|
23
|
+
}
|
|
29
24
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
port: seleniumPort
|
|
35
|
-
},
|
|
36
|
-
webdriver: {
|
|
37
|
-
start_process: false
|
|
38
|
-
},
|
|
39
|
-
desiredCapabilities: {
|
|
40
|
-
browserName: "chrome",
|
|
41
|
-
chromeOptions: {
|
|
42
|
-
args: [
|
|
43
|
-
"--headless",
|
|
44
|
-
"--no-sandbox",
|
|
45
|
-
"--disable-gpu"
|
|
46
|
-
]
|
|
25
|
+
|
|
26
|
+
test_settings: {
|
|
27
|
+
default: {
|
|
28
|
+
launch_url: launchUrl
|
|
47
29
|
},
|
|
48
|
-
|
|
49
|
-
|
|
30
|
+
'selenium.chrome': {
|
|
31
|
+
selenium: {
|
|
32
|
+
start_process: false,
|
|
33
|
+
host: seleniumHost,
|
|
34
|
+
port: seleniumPort
|
|
35
|
+
},
|
|
36
|
+
webdriver: {
|
|
37
|
+
start_process: false
|
|
38
|
+
},
|
|
39
|
+
desiredCapabilities: {
|
|
40
|
+
browserName: 'chrome',
|
|
41
|
+
chromeOptions: {
|
|
42
|
+
args: [
|
|
43
|
+
'--headless',
|
|
44
|
+
'--no-sandbox',
|
|
45
|
+
'--disable-gpu'
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
acceptSslCerts: true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
50
51
|
}
|
|
51
|
-
}
|
|
52
52
|
}
|
package/package.json
CHANGED
package/wrap.js
CHANGED
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
*/
|
|
42
42
|
export function wrap(args) {
|
|
43
43
|
if (!args) {
|
|
44
|
-
throw Error(
|
|
44
|
+
throw Error('Parameter args is required')
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// We need to have one and only one of component and asyncComponent
|
|
48
48
|
// This does a "XNOR"
|
|
49
49
|
if (!args.component == !args.asyncComponent) {
|
|
50
|
-
throw Error(
|
|
50
|
+
throw Error('One and only one of component and asyncComponent is required')
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// If the component is not async, wrap it into a function returning a Promise
|
|
@@ -56,8 +56,8 @@ export function wrap(args) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// Parameter asyncComponent and each item of conditions must be functions
|
|
59
|
-
if (typeof args.asyncComponent !=
|
|
60
|
-
throw Error(
|
|
59
|
+
if (typeof args.asyncComponent != 'function') {
|
|
60
|
+
throw Error('Parameter asyncComponent must be a function')
|
|
61
61
|
}
|
|
62
62
|
if (args.conditions) {
|
|
63
63
|
// Ensure it's an array
|
|
@@ -65,8 +65,8 @@ export function wrap(args) {
|
|
|
65
65
|
args.conditions = [args.conditions]
|
|
66
66
|
}
|
|
67
67
|
for (let i = 0; i < args.conditions.length; i++) {
|
|
68
|
-
if (!args.conditions[i] || typeof args.conditions[i] !=
|
|
69
|
-
throw Error(
|
|
68
|
+
if (!args.conditions[i] || typeof args.conditions[i] != 'function') {
|
|
69
|
+
throw Error('Invalid parameter conditions[' + i + ']')
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|