@keenmate/svelte-spa-router 1.0.1 → 1.0.3

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 ADDED
@@ -0,0 +1,21 @@
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
+ ij_html_quote_style = double
11
+ ij_javascript_use_double_quotes = true
12
+ ij_typescript_use_double_quotes = true
13
+
14
+ [*.{xaml,cshtml,html,xml}]
15
+ indent_style = tab
16
+ indent_size = 2
17
+ trim_trailing_whitespace = true
18
+ charset = utf-8
19
+
20
+ [*.cs]
21
+ 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
@@ -15,29 +15,35 @@
15
15
  */
16
16
  function getLocation() {
17
17
  const hashRoutingEnabled = get(HashRoutingEnabled)
18
- const basePath = get(BasePath)
19
- let location
18
+ const basePath = get(BasePath)
19
+ let location = ""
20
+ let querystring = ""
20
21
 
21
22
  if (hashRoutingEnabled) {
22
23
  const hashPosition = window.location.href.indexOf("#/")
23
24
  location = (hashPosition > -1) ?
24
25
  window.location.href.substr(hashPosition + 1) :
25
26
  "/"
26
- } else {
27
+
28
+ // Check if there's a querystring
29
+ const qsPosition = location.indexOf("?")
30
+ if (qsPosition > -1) {
31
+ querystring = location.substr(qsPosition + 1)
32
+ location = location.substr(0, qsPosition)
33
+ }
34
+ }
35
+ else {
27
36
  const startsWithPrefix = window.location.pathname.startsWith(basePath)
28
37
  if (!hashRoutingEnabled && !startsWithPrefix) {
29
- throw new Error(`Hash routing disabled and location: "${window.location.href}" does not start with expected base path: "${get(BasePath)}"`)
38
+ throw new Error(`Hash routing disabled and location: "${window.location.href}" does not start with expected base path: "${get(
39
+ BasePath)}"`)
30
40
  }
31
41
 
32
- location = "/" + window.location.pathname.substring(basePath.length)
33
- }
34
-
35
- // Check if there's a querystring
36
- const qsPosition = location.indexOf("?")
37
- let querystring = ""
38
- if (qsPosition > -1) {
39
- querystring = location.substr(qsPosition + 1)
40
- location = location.substr(0, qsPosition)
42
+ location = "/" + window.location.pathname.substring(basePath.length).replace(/^\//, "")
43
+ // console.log("SAPA ROUTER Parsing querystring", window.location.search)
44
+ if (window.location.search) {
45
+ querystring = window.location.search.substring(1)
46
+ }
41
47
  }
42
48
 
43
49
  return {location, querystring}
@@ -55,7 +61,7 @@
55
61
  const eventName = get(HashRoutingEnabled) ?
56
62
  "hashchange" :
57
63
  SvelteSPARouterNavigationEvent
58
- console.log("Setting loc")
64
+ // console.log("Setting loc")
59
65
  const update = () => {
60
66
  console.log("Updating location", getLocation())
61
67
  set(getLocation())
@@ -123,16 +129,17 @@
123
129
  return jediForcePush(location, true)
124
130
  }
125
131
 
126
- async function jediForcePush(location, shouldReplace = false) {
132
+ async function jediForcePush(location_, shouldReplace = false) {
127
133
  const hashRoutingEnabled = get(HashRoutingEnabled)
128
- const basePath = get(BasePath)
134
+ const basePath = get(BasePath)
129
135
 
130
136
  if (hashRoutingEnabled) {
131
- if (!location || location.length < 1 || !/^(\/|#\/)/.test(location)) {
137
+ if (!location_ || location_.length < 1 || !/^(\/|#\/)/.test(location_)) {
132
138
  throw Error("Invalid parameter location")
133
139
  }
134
- } else {
135
- if (!location || location.length < 1 || !/^\//.test(location)) {
140
+ }
141
+ else {
142
+ if (!location_ || location_.length < 1 || !/^\//.test(location_)) {
136
143
  throw Error("Invalid parameter location")
137
144
  }
138
145
  }
@@ -155,26 +162,29 @@
155
162
  doNavigate(newHistoryState, undefined)
156
163
 
157
164
  if (!shouldReplace) {
158
- window.location.hash = (location.charAt(0) === "#" ? "" : "#") + location
159
- } else {
165
+ window.location.hash = (location_.charAt(0) === "#" ? "" : "#") + location_
166
+ }
167
+ else {
160
168
  window.dispatchEvent(new Event("hashchange"))
161
169
  }
162
170
  } else {
163
- if (!location.startsWith(basePath)) {
164
- location = joinPaths(basePath, location)
165
- }
166
-
167
- console.log(
168
- "Before navigate",
169
- window.history,
170
- window.history.pushState,
171
- doNavigate,
172
- newHistoryState,
173
- undefined,
174
- location
175
- )
176
- // window.history.pushState(newHistoryState, undefined, location)
177
- doNavigate(newHistoryState, undefined, location)
171
+ if (location_ !== get(location)) {
172
+ if (!location_.startsWith(basePath)) {
173
+ location_ = joinPaths(basePath, location_)
174
+ }
175
+
176
+ // console.log(
177
+ // "Before navigate",
178
+ // window.history,
179
+ // window.history.pushState,
180
+ // doNavigate,
181
+ // newHistoryState,
182
+ // undefined,
183
+ // location_
184
+ // )
185
+ // window.history.pushState(newHistoryState, undefined, location)
186
+ doNavigate(newHistoryState, undefined, location_)
187
+ }
178
188
 
179
189
  window.dispatchEvent(new Event(SvelteSPARouterNavigationEvent))
180
190
  }
@@ -185,7 +195,7 @@
185
195
  * @typedef {Object} LinkActionOpts
186
196
  * @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
197
  * @property {boolean} disabled - If true, link is disabled
188
- * @property {boolean} shouldReplace - If true, link will replace instead of push new history entry
198
+ * @property {boolean} replace - If true, link will replace instead of push new history entry
189
199
  */
190
200
 
191
201
  /**
@@ -205,20 +215,26 @@
205
215
 
206
216
  // Only apply to <a> tags
207
217
  if (!node || !node.tagName || node.tagName.toLowerCase() != "a") {
208
- throw Error("Action \"link\" can only be used with <a> tags")
218
+ throw Error("Action 'link' can only be used with <a> tags")
209
219
  }
210
220
 
211
221
  updateLink(node, opts)
212
222
 
213
223
  if (!get(HashRoutingEnabled)) {
214
224
  node.addEventListener("click", ev => {
225
+ const linkTarget = ev.target.getAttribute("target")
226
+ if (linkTarget && linkTarget !== "_self") {
227
+ // prevent pushState when link is perhaps going outside of this window
228
+ return
229
+ }
230
+
215
231
  ev.stopImmediatePropagation()
216
232
  ev.preventDefault()
217
233
 
218
234
  const shouldReplace = typeof opts !== "string" && opts.shouldReplace
219
235
 
220
236
  jediForcePush(node.getAttribute("href"), shouldReplace)
221
- window.dispatchEvent(new Event(SvelteSPARouterNavigationEvent))
237
+ // window.dispatchEvent(new Event(SvelteSPARouterNavigationEvent))
222
238
  }, {capture: true})
223
239
  }
224
240
 
@@ -239,7 +255,8 @@
239
255
  // If this exists, then this is a back navigation: restore the scroll position
240
256
  if (state) {
241
257
  window.scrollTo(state.__svelte_spa_router_scrollX, state.__svelte_spa_router_scrollY)
242
- } else {
258
+ }
259
+ else {
243
260
  // Otherwise this is a forward navigation: scroll to top
244
261
  window.scrollTo(0, 0)
245
262
  }
@@ -255,10 +272,12 @@
255
272
  if (href && href.charAt(0) == "/") {
256
273
  // Add # to the href attribute
257
274
  href = "#" + href
258
- } else if (!href || href.length < 2 || href.slice(0, 2) != "#/") {
275
+ }
276
+ else if (!href || href.length < 2 || href.slice(0, 2) != "#/") {
259
277
  throw Error("Invalid value for \"href\" attribute: " + href)
260
278
  }
261
- } else {
279
+ }
280
+ else {
262
281
  if (href && !href.startsWith(basePath)) {
263
282
  href = joinPaths(basePath, href)
264
283
  }
@@ -280,7 +299,8 @@
280
299
  return {
281
300
  href: val
282
301
  }
283
- } else {
302
+ }
303
+ else {
284
304
  return val || {}
285
305
  }
286
306
  }
@@ -383,7 +403,8 @@
383
403
  this.conditions = component.conditions || []
384
404
  this.userData = component.userData
385
405
  this.props = component.props || {}
386
- } else {
406
+ }
407
+ else {
387
408
  // Convert the component to a function that returns a Promise, to normalize it
388
409
  this.component = () => Promise.resolve(component)
389
410
  this.conditions = []
@@ -409,14 +430,17 @@
409
430
  if (typeof prefix == "string") {
410
431
  if (path.startsWith(prefix)) {
411
432
  path = path.substr(prefix.length) || "/"
412
- } else {
433
+ }
434
+ else {
413
435
  return null
414
436
  }
415
- } else if (prefix instanceof RegExp) {
437
+ }
438
+ else if (prefix instanceof RegExp) {
416
439
  const match = path.match(prefix)
417
440
  if (match && match[0]) {
418
441
  path = path.substr(match[0].length) || "/"
419
- } else {
442
+ }
443
+ else {
420
444
  return null
421
445
  }
422
446
  }
@@ -482,7 +506,8 @@
482
506
  routes.forEach((route, path) => {
483
507
  routesList.push(new RouteItem(path, route))
484
508
  })
485
- } else {
509
+ }
510
+ else {
486
511
  // We have an object, so iterate on its own properties
487
512
  Object.keys(routes).forEach((path) => {
488
513
  routesList.push(new RouteItem(path, routes[path]))
@@ -517,7 +542,8 @@
517
542
  // navigation)
518
543
  if (event.state && (event.state.__svelte_spa_router_scrollY || event.state.__svelte_spa_router_scrollX)) {
519
544
  previousScrollState = event.state
520
- } else {
545
+ }
546
+ else {
521
547
  previousScrollState = null
522
548
  }
523
549
  }
@@ -589,7 +615,8 @@
589
615
  name: component.name,
590
616
  params: componentParams
591
617
  }))
592
- } else {
618
+ }
619
+ else {
593
620
  component = null
594
621
  componentObj = null
595
622
  }
@@ -612,7 +639,8 @@
612
639
  // Of course, this assumes that developers always add a "params" prop when they are expecting parameters
613
640
  if (match && typeof match == "object" && Object.keys(match).length) {
614
641
  componentParams = match
615
- } else {
642
+ }
643
+ else {
616
644
  componentParams = null
617
645
  }
618
646
 
package/active.js CHANGED
@@ -1,6 +1,6 @@
1
- import {parse} from "regexparam"
2
- import {BasePath, HashRoutingEnabled, loc} from "./Router.svelte"
3
- import {get} from "svelte/store"
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 || "").split(" ").forEach((cls) => {
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 ? "?" + 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 == "string" || (typeof opts == "object" && opts instanceof RegExp))) {
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
- } else {
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("href")) {
71
- opts.path = node.getAttribute("href")
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
- } else {
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 = "active"
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 == "string" && (opts.path.length < 1 || (opts.path.charAt(0) != "/" && opts.path.charAt(0) != "*"))
93
+ typeof opts.path == 'string' && (opts.path.length < 1 || (opts.path.charAt(0) != '/' && opts.path.charAt(0) != '*'))
92
94
  ) {
93
- throw Error("Invalid value for \"path\" argument")
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 == "string" ?
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 = "popstate"
1
+ export const SvelteSPARouterNavigationEvent = 'popstate'
@@ -1,52 +1,52 @@
1
1
  // Selenium configuration
2
- const seleniumHost = process.env.SELENIUM_HOST || "127.0.0.1"
3
- const seleniumPort = parseInt(process.env.SELENIUM_PORT || "4444", 10)
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 || "http://localhost:5050"
6
+ const launchUrl = process.env.LAUNCH_URL || 'http://localhost:5050'
7
7
 
8
8
  // Increase max listeners to avoid a warning
9
- require("events").EventEmitter.defaultMaxListeners = 100
9
+ require('events').EventEmitter.defaultMaxListeners = 100
10
10
 
11
11
  module.exports = {
12
- src_folders: [
13
- "test/cases/"
14
- ],
12
+ src_folders: [
13
+ 'test/cases/'
14
+ ],
15
15
 
16
- output_folder: "result",
16
+ output_folder: 'result',
17
17
 
18
- test_runner: {
19
- type: "mocha",
20
- options: {
21
- ui: "bdd",
22
- reporter: "list"
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
- "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
- ]
25
+
26
+ test_settings: {
27
+ default: {
28
+ launch_url: launchUrl
47
29
  },
48
- acceptSslCerts: true
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@keenmate/svelte-spa-router",
3
3
  "private": false,
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "description": "Router for SPAs using Svelte 4",
6
6
  "main": "Router.svelte",
7
7
  "svelte": "Router.svelte",
package/wrap.js CHANGED
@@ -41,13 +41,13 @@
41
41
  */
42
42
  export function wrap(args) {
43
43
  if (!args) {
44
- throw Error("Parameter args is required")
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("One and only one of component and asyncComponent is required")
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 != "function") {
60
- throw Error("Parameter asyncComponent must be a function")
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] != "function") {
69
- throw Error("Invalid parameter conditions[" + i + "]")
68
+ if (!args.conditions[i] || typeof args.conditions[i] != 'function') {
69
+ throw Error('Invalid parameter conditions[' + i + ']')
70
70
  }
71
71
  }
72
72
  }