nanosplash 2.4.0 → 2.5.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.
@@ -1,20 +1,31 @@
1
1
  import '../style.sass'
2
+ import {get} from "../Utilities/dom";
2
3
  import {SplashInstance} from "./SplashInstance";
3
- import {InstanceIterationCallback, NanosplashOptions, SplashJob} from "../types";
4
4
  import {ShowInterface} from "../Interfaces/ShowInterface";
5
5
  import {NanosplashFactory} from "../Factory/NanosplashFactory";
6
6
  import {NanosplashInterface} from "../Interfaces/NanosplashInterface";
7
- import {ContextualAPIInterface} from "../Interfaces/ContextualAPIInterface";
7
+ import {
8
+ ContextualAPIObject,
9
+ Destination,
10
+ InstanceIterationCallback,
11
+ NanosplashOptions,
12
+ SplashJob,
13
+ } from "../types";
14
+ import Exception from "../Exceptions/Exception";
15
+ import IllegalArgumentException from "../Exceptions/IllegalArgumentException";
8
16
 
9
17
  /**
10
18
  * # Nanosplash
11
19
  * @author Isak K. Hauge <isakhauge@gmail.com>
12
20
  */
13
- export class Nanosplash implements NanosplashInterface {
21
+ class Nanosplash implements NanosplashInterface {
14
22
  public static APP_NAME = 'Nanosplash'
15
- public imgSrc: string | undefined
16
- public showSpinner: boolean
17
- public fontSize: string
23
+ private static SPINNER_DEFAULT_VISIBILITY = true
24
+ private static DEBUG = true
25
+ public debug: boolean
26
+ private imgSrc: string | undefined
27
+ private spinner: boolean
28
+ private fontSize: string
18
29
  public readonly instances: Map<string, SplashInstance>
19
30
 
20
31
  /**
@@ -22,33 +33,92 @@ export class Nanosplash implements NanosplashInterface {
22
33
  * @param {NanosplashOptions | undefined} options Nanosplash options object.
23
34
  */
24
35
  public constructor(options?: NanosplashOptions) {
25
- this.imgSrc = options?.imgSrc ?? undefined
26
- this.showSpinner = options?.spinner ?? false
36
+ this.debug = ((options?.debug === undefined)
37
+ ? Nanosplash.DEBUG
38
+ : options.spinner) as boolean
39
+ this.imgSrc = options?.imgSrc
40
+ this.spinner = (options?.spinner === undefined)
41
+ ? Nanosplash.SPINNER_DEFAULT_VISIBILITY
42
+ : options.spinner
27
43
  this.fontSize = options?.fontSize ?? '18px'
28
44
  this.instances = new Map<string, SplashInstance>()
29
45
  }
30
46
 
47
+ /**
48
+ * # Set Image Source
49
+ * Set the value as undefined to display no image.
50
+ * @param {string | undefined} value
51
+ * @return Nanosplash
52
+ */
53
+ public setImgSrc(value: string | undefined): Nanosplash {
54
+ this.imgSrc = value
55
+ return this
56
+ }
57
+
58
+ /**
59
+ * # Set Spinner
60
+ * Control spinner visibility.
61
+ * @param {boolean} value
62
+ * @return Nanosplash
63
+ */
64
+ public showSpinner(value: boolean): Nanosplash {
65
+ this.spinner = value
66
+ return this
67
+ }
68
+
69
+ /**
70
+ * # Set Font Size
71
+ * @param {string} value Use CSS compatible values.
72
+ * @return Nanosplash
73
+ */
74
+ public setFontSize(value: string): Nanosplash {
75
+ this.fontSize = value
76
+ return this
77
+ }
78
+
79
+ /**
80
+ * # Get Image Source
81
+ * @return string | undefined
82
+ */
83
+ public getImgSrc(): string | undefined {
84
+ return this.imgSrc
85
+ }
86
+
87
+ /**
88
+ * # Spinner Is Visible
89
+ * @return boolean
90
+ */
91
+ public spinnerIsVisible(): boolean {
92
+ return this.spinner
93
+ }
94
+
95
+ /**
96
+ * # Get Font Size
97
+ * @return string
98
+ */
99
+ public getFontSize(): string {
100
+ return this.fontSize
101
+ }
102
+
31
103
  /**
32
104
  * # Show
33
105
  * @param {string} text
34
106
  */
35
- public show(text: string): ContextualAPIInterface {
107
+ public show(text: string): ContextualAPIObject {
36
108
  return NanosplashFactory.createShowFunction(this, new SplashInstance(this, text, this.imgSrc))(text)
37
109
  }
38
110
 
39
111
  /**
40
112
  * # Progress
41
113
  * @param {SplashJob[]} jobs An array or list of Splash jobs.
42
- * @return ContextualAPIInterface
43
114
  */
44
- public progress(...jobs: SplashJob[]): ContextualAPIInterface {
115
+ public progress(...jobs: SplashJob[]): ContextualAPIObject {
45
116
  return NanosplashFactory.createProgressFunction(this, new SplashInstance(this, '', this.imgSrc))(...jobs)
46
117
  }
47
118
 
48
119
  /**
49
120
  * # While
50
121
  * @param {Promise<any>} asyncTask An asynchronous function or Promise.
51
- * @return ContextualAPIInterface
52
122
  */
53
123
  public while(asyncTask: Promise<any>): ShowInterface {
54
124
  return NanosplashFactory.createWhileFunction(this, new SplashInstance(this, '', this.imgSrc))(asyncTask)
@@ -65,11 +135,6 @@ export class Nanosplash implements NanosplashInterface {
65
135
  const n = this.instances.size
66
136
  const instances = Array.from(this.instances.values())
67
137
  for (let i = n - 1; i >= 0; i--) {
68
- console.log({
69
- size: n,
70
- lastIdx: n - 1,
71
- currentIdx: i
72
- })
73
138
  const instance = instances[i]
74
139
  const id = instance.getId()
75
140
  if (!callback(id, instance, i)) {
@@ -97,39 +162,96 @@ export class Nanosplash implements NanosplashInterface {
97
162
 
98
163
  /**
99
164
  * # Hide
100
- * Delete specific Splash instance or the latest one.
101
- * @param id
165
+ * Delete specific Splash instance or the latest one. There are three different ways of using this function.
166
+ *
167
+ * ## Use SplashInstance IDs
168
+ * Every new splash instance is given a unique, randomized ID. This ID is easily retrieved by using the getId
169
+ * method.
170
+ * <br>
171
+ * <code>
172
+ * const splashInstance = ns.show('Loading');<br>
173
+ * ns.hide(splashInstance.getId());
174
+ * </code>
175
+ * <br>
176
+ *
177
+ * ## Use CSS Selector
178
+ * Pass the selector referring to the element in which the splash instance resides.
179
+ * <br>
180
+ * <code>
181
+ * ns.show('Loading').inside('#my-div');<br>
182
+ * ns.hide('#my-div');
183
+ * </code>
184
+ * <br>
185
+ *
186
+ * ## Pass no argument
187
+ * When calling the hide method without passing arguments, it will delete the latest splash instance added to the
188
+ * DOM, in other words, in a LIFO fashion.<br>
189
+ * <code>
190
+ * ns.show('Loading');<br>
191
+ * ns.hide();
192
+ * </code>
193
+ * <br>
194
+ * @param ref This can either be a SplashInstance ID or a CSS selector referring to the element in which
195
+ * the instance is residing.
102
196
  */
103
- public hide(id?: string): void {
104
- if (id) {
105
- const splashInstance = this.instances.get(id)
106
- if (splashInstance) {
107
- splashInstance.delete()
197
+ public hide(ref?: Destination): void {
198
+ try {
199
+ if (ref) {
200
+ const isString = typeof ref === 'string'
201
+ const isNode = ref instanceof Node
202
+ const deleteInstancesWhereDestination = (destination: Destination) => {
203
+ Array.from(this.instances.values())
204
+ .filter((v: SplashInstance) => v.getDestination() === destination)
205
+ .forEach((v: SplashInstance) => v.delete())
206
+ }
207
+
208
+ if (isString) {
209
+ const splashInstance = this.instances.get(ref)
210
+ if (splashInstance) {
211
+ splashInstance.delete()
212
+ return
213
+ } else {
214
+ const element = get<HTMLElement>(ref)
215
+ if (element) {
216
+ deleteInstancesWhereDestination(element)
217
+ }
218
+ throw new Exception(`The CSS selector (${ref}) points to a non-existing DOM element.`)
219
+ }
220
+ } else if (isNode) {
221
+ deleteInstancesWhereDestination(ref)
222
+ } else {
223
+ throw new IllegalArgumentException(
224
+ 'The ref argument must be either a string or Node',
225
+ ref
226
+ )
227
+ }
108
228
  } else {
109
- throw new Error(
110
- `Could not find element with id: ${id}`
111
- )
229
+ const n = this.instances.size
230
+ this.lifoIterate((_: string, splashInstance: SplashInstance, i: number) => {
231
+ const remove = i === n - 1
232
+ if (remove) {
233
+ splashInstance.delete()
234
+ }
235
+ return remove
236
+ })
237
+ }
238
+ } catch (e) {
239
+ if (this.debug) {
240
+ console.warn(e)
112
241
  }
113
- } else {
114
- const n = this.instances.size
115
- this.lifoIterate((_: string, splashInstance: SplashInstance, i: number) => {
116
- const remove = i === n - 1
117
- if (remove) {
118
- splashInstance.delete()
119
- }
120
- return remove
121
- })
122
242
  }
123
243
  }
124
244
 
125
245
  /**
126
- * # Get Splashes With Destination Node
246
+ * # Get From Destination Node
127
247
  * Returns Splash instances having the given destination node.
128
248
  * @param {HTMLElement} node
129
249
  */
130
- public getSplashesWithDestinationNode(node: HTMLElement): SplashInstance[]
250
+ public getFromDestinationNode(node: HTMLElement): SplashInstance[]
131
251
  {
132
252
  const fnSameDestinationNode = (v: SplashInstance) => v.getDestination() === node
133
253
  return Array.from(this.instances.values()).filter(fnSameDestinationNode)
134
254
  }
135
255
  }
256
+
257
+ export default Nanosplash
@@ -1,8 +1,8 @@
1
1
  import {Destination} from "../types";
2
- import {Nanosplash} from "./Nanosplash";
3
- import {addClass, mk, move, setAttr} from "../utilities/dom";
2
+ import Nanosplash from "./Nanosplash";
3
+ import {addClass, mk, move, setAttr} from "../Utilities/dom";
4
4
  import {IdentityInterface} from "../Interfaces/IdentityInterface";
5
- import {NanosplashRepository} from "../repositories/NanosplashRepository";
5
+ import {NanosplashRepository} from "../Repositories/NanosplashRepository";
6
6
 
7
7
  /**
8
8
  * SplashInstance
@@ -36,8 +36,8 @@ export class SplashInstance implements IdentityInterface {
36
36
  this.nsImageElement.src = this.imgSrc ?? ''
37
37
  this.nsImageElement.alt = Nanosplash.APP_NAME
38
38
 
39
- this.nsRootElement.style.fontSize = ns.fontSize
40
- this.nsSpinnerElement.style.display = ns.showSpinner ? 'flex' : 'none'
39
+ this.nsRootElement.style.fontSize = ns.getFontSize()
40
+ this.nsSpinnerElement.style.display = ns.spinnerIsVisible() ? 'flex' : 'none'
41
41
 
42
42
  this.assembleNSComponent()
43
43
  this.setImgSrc(imgSrc)
@@ -169,7 +169,7 @@ export class SplashInstance implements IdentityInterface {
169
169
  }
170
170
 
171
171
  /**
172
- * # Move with Regular Strategy
172
+ * # Move With Regular Strategy
173
173
  * Moves the Nanosplash root element to the target node's position and essentially wraps the target node with the
174
174
  * Nanosplash root element.
175
175
  * @param {Node} targetNode
@@ -206,7 +206,7 @@ export class SplashInstance implements IdentityInterface {
206
206
  {
207
207
  const fnNotSameInstance = (v: SplashInstance) => v.getId() !== this.getId()
208
208
  const fnDelete = (v: SplashInstance) => v.delete()
209
- this.nsInstance.getSplashesWithDestinationNode(destinationNode).filter(fnNotSameInstance).forEach(fnDelete)
209
+ this.nsInstance.getFromDestinationNode(destinationNode).filter(fnNotSameInstance).forEach(fnDelete)
210
210
  }
211
211
 
212
212
  /**
@@ -216,28 +216,34 @@ export class SplashInstance implements IdentityInterface {
216
216
  */
217
217
  public moveTo(destination: Destination): void
218
218
  {
219
- // Clean up and restore previous location if any.
220
- this.cleanAndRestore()
219
+ try {
220
+ // Clean up and restore previous location if any.
221
+ this.cleanAndRestore()
221
222
 
222
- // Convert the destination into a DOM Node
223
- this.destinationNode = NanosplashRepository.destinationToNode(destination)
223
+ // Convert the destination into a DOM Node
224
+ this.destinationNode = NanosplashRepository.destinationToNode(destination)
224
225
 
225
- // Replace splash instances having the same destination node
226
- this.replaceSplashInstancesHavingSameDestination(this.destinationNode)
226
+ // Replace splash instances having the same destination node
227
+ this.replaceSplashInstancesHavingSameDestination(this.destinationNode)
227
228
 
228
- // Assess whether the destination node is the Document body or not
229
- const targetIsBody = this.destinationNode === document.body
229
+ // Assess whether the destination node is the Document body or not
230
+ const targetIsBody = this.destinationNode === document.body
230
231
 
232
+ if (targetIsBody) {
233
+ this.moveWithFullscreenStrategy()
234
+ } else {
235
+ this.resetFullscreenAttributes()
236
+ this.moveWithRegularStrategy(this.destinationNode)
237
+ }
231
238
 
232
- if (targetIsBody) {
233
- this.moveWithFullscreenStrategy()
234
- } else {
235
- this.resetFullscreenAttributes()
236
- this.moveWithRegularStrategy(this.destinationNode)
239
+ // Assemble the Nanosplash component
240
+ this.assembleNSComponent()
241
+ } catch (e) {
242
+ this.delete()
243
+ if (this.nsInstance.debug) {
244
+ console.warn(e)
245
+ }
237
246
  }
238
-
239
- // Assemble the Nanosplash component
240
- this.assembleNSComponent()
241
247
  }
242
248
 
243
249
  /**
@@ -0,0 +1,13 @@
1
+ import Exception from "./Exception";
2
+ import {Destination} from "../types";
3
+
4
+ class DestinationException extends Exception {
5
+ public destination: Destination
6
+ public constructor(message: string, destination: Destination, cause: Exception) {
7
+ super(message);
8
+ this.destination = destination
9
+ this.cause = cause
10
+ }
11
+ }
12
+
13
+ export default DestinationException
@@ -0,0 +1,9 @@
1
+ class Exception extends Error {
2
+ public constructor(message?: string, cause?: Exception) {
3
+ super(message);
4
+ this.name = this.constructor.name
5
+ this.cause = cause
6
+ }
7
+ }
8
+
9
+ export default Exception
@@ -0,0 +1,11 @@
1
+ import Exception from "./Exception";
2
+
3
+ class IllegalArgumentException extends Exception {
4
+ public argument: any
5
+ public constructor(message: string, argument: any) {
6
+ super(message);
7
+ this.argument = argument
8
+ }
9
+ }
10
+
11
+ export default IllegalArgumentException
@@ -1,9 +1,23 @@
1
- import {ProgressFunction, ShowFunction, SplashJob, WhileFunction} from "../types";
2
- import {Nanosplash} from "../Core/Nanosplash";
1
+ import Nanosplash from "../Core/Nanosplash";
3
2
  import {SplashInstance} from "../Core/SplashInstance";
4
- import {NanosplashRepository} from "../repositories/NanosplashRepository";
3
+ import {NanosplashRepository} from "../Repositories/NanosplashRepository";
4
+ import {ContextualAPIObject, ProgressFunction, ShowFunction, SplashJob, WhileFunction} from "../types";
5
+ import {ShowInterface} from "../Interfaces/ShowInterface";
5
6
 
7
+ /**
8
+ * # Nanosplash Factory
9
+ * @author Isak K. Hauge
10
+ */
6
11
  export class NanosplashFactory {
12
+ /**
13
+ * # Ensure Instance
14
+ * Returns and modifies the splash instance, or creates a new one.
15
+ * @param {SplashInstance | null} splash Splash instance
16
+ * @param {Nanosplash} ns Nanosplash instance
17
+ * @param {string} text Splash text
18
+ * @param {string | undefined} imgSrc Splash image URL
19
+ * @private
20
+ */
7
21
  private static ensureInstance(
8
22
  splash: SplashInstance | null,
9
23
  ns: Nanosplash,
@@ -17,9 +31,15 @@ export class NanosplashFactory {
17
31
  return splash.setText(text).setImgSrc(splash.getImgSrc() ?? imgSrc)
18
32
  }
19
33
 
34
+ /**
35
+ * # Create Show Function
36
+ * @param ns
37
+ * @param splash
38
+ * @return {ShowFunction} A curried function made for a specific splash instance.
39
+ */
20
40
  public static createShowFunction(ns: Nanosplash, splash: SplashInstance | null): ShowFunction
21
41
  {
22
- return (text: string) => {
42
+ return (text: string): ContextualAPIObject => {
23
43
  splash = NanosplashFactory.ensureInstance(splash, ns, text)
24
44
  ns.instances.set(splash.getId(), splash)
25
45
  splash.moveTo(document.body)
@@ -27,6 +47,12 @@ export class NanosplashFactory {
27
47
  }
28
48
  }
29
49
 
50
+ /**
51
+ * # Create Progress Function
52
+ * @param ns
53
+ * @param splash
54
+ * @return {ProgressFunction} A curried API function made for a specific splash instance.
55
+ */
30
56
  public static createProgressFunction(ns: Nanosplash, splash: SplashInstance | null): ProgressFunction
31
57
  {
32
58
  return (...jobs: SplashJob[]) => {
@@ -43,9 +69,15 @@ export class NanosplashFactory {
43
69
  }
44
70
  }
45
71
 
72
+ /**
73
+ * # Create While Function
74
+ * @param ns
75
+ * @param splash
76
+ * @return {ProgressFunction} A curried API function made for a specific splash instance.
77
+ */
46
78
  public static createWhileFunction(ns: Nanosplash, splash: SplashInstance): WhileFunction
47
79
  {
48
- return (asyncTask: Promise<any>) => {
80
+ return (asyncTask: Promise<any>): ShowInterface => {
49
81
  splash = NanosplashFactory.ensureInstance(splash, ns, '')
50
82
  return {
51
83
  show(text: string) {
@@ -1,3 +1,8 @@
1
1
  import {StrategyObject} from "../types";
2
+ import {SplashInstance} from "../Core/SplashInstance";
2
3
 
3
- export interface NanosplashInterface extends StrategyObject {}
4
+ export interface NanosplashInterface extends StrategyObject {
5
+ delete(splashInstance: SplashInstance): void
6
+ hideAll(): void
7
+ hide(id?: string): void
8
+ }
@@ -1,22 +1,49 @@
1
- import {addClass, get, mk} from "../utilities/dom";
1
+ import Exception from "../Exceptions/Exception";
2
+ import {addClass, get, mk} from "../Utilities/dom";
2
3
  import {SplashInstance} from "../Core/SplashInstance";
3
4
  import {ContextualAPIObject, Destination} from "../types";
5
+ import DestinationException from "../Exceptions/DestinationException";
6
+ import IllegalArgumentException from "../Exceptions/IllegalArgumentException";
4
7
 
5
8
  export class NanosplashRepository {
9
+ /**
10
+ * # Destination To Node
11
+ * Converts a Destination type into an HTMLElement.
12
+ * @param {Destination} destination Either a node or a CSS selector.
13
+ * @throws DestinationException
14
+ * @throws IllegalArgumentException
15
+ */
6
16
  public static destinationToNode(destination: Destination): HTMLElement
7
17
  {
8
18
  if (typeof destination === 'string') {
9
- const element = get<HTMLElement>(destination)
10
- if (!element) {
11
- throw new Error(`No match with ${destination}`)
19
+ try {
20
+ const element = get<HTMLElement>(destination)
21
+ if (!element) {
22
+ throw new Exception(`No DOM match with ${destination}`)
23
+ }
24
+ return element
25
+ } catch (e) {
26
+ throw new DestinationException(
27
+ `Destination (${destination}) is either invalid or non-existing in DOM`,
28
+ destination,
29
+ e as Exception
30
+ )
12
31
  }
13
- return element
14
32
  } else if (destination instanceof Node) {
15
33
  return destination as HTMLElement
16
34
  }
17
- throw new Error('Destination argument must string or Node')
35
+
36
+ throw new IllegalArgumentException(
37
+ `Destination (${destination}) must be either a Node or a CSS selector`,
38
+ destination
39
+ )
18
40
  }
19
41
 
42
+ /**
43
+ * # Create Contextual API Object
44
+ * Creates an object containing props that adhere to the ns API.
45
+ * @param {SplashInstance} splash
46
+ */
20
47
  public static createContextualApiObject(splash: SplashInstance): ContextualAPIObject
21
48
  {
22
49
  const ctx = {
@@ -37,6 +64,10 @@ export class NanosplashRepository {
37
64
  }
38
65
  }
39
66
 
67
+ /**
68
+ * # Create Nanosplash Spinner Element
69
+ * Returns a DIV element wrapping an SVG element.
70
+ */
40
71
  public static createNanosplashSpinnerElement(): HTMLDivElement
41
72
  {
42
73
  const div = mk('div') as HTMLDivElement
@@ -1,8 +1,9 @@
1
- import {addClass, get, mk, move, setAttr} from "./dom";
1
+ import {test} from "vitest"
2
+ import {addClass, get, mk, move, setAttr} from "../Utilities/dom"
2
3
 
3
4
  const resetDOM = () => document.body.innerHTML = ''
4
5
 
5
- test('Single DOM get function', () => {
6
+ test('Get DOM element function', () => {
6
7
  const element = document.createElement('div')
7
8
  element.id = 'a'
8
9
  element.classList.add('b')
@@ -48,9 +49,10 @@ test('Move Element from origin to destination', () => {
48
49
  })
49
50
 
50
51
  test('Make HTML Element', () => {
51
- document.body.appendChild(mk('span'))
52
- const span = document.body.children.item(0) as Node
53
- expect(span instanceof HTMLSpanElement).toBe(true)
52
+ const span = mk('span')
53
+ document.body.appendChild(span)
54
+ const spanFromDom = document.body.children.item(0) as Node
55
+ expect(spanFromDom instanceof HTMLSpanElement).toBe(true)
54
56
  resetDOM()
55
57
  })
56
58
 
@@ -1,9 +1,21 @@
1
1
  import {ElementTag} from "../types";
2
2
 
3
+ /**
4
+ * # Get
5
+ * Helper function to get Elements from the DOM using CSS selector.
6
+ * @param {string} selector CSS Selector.
7
+ */
3
8
  export function get<T>(selector: string): HTMLElement | T | null {
4
9
  return document.querySelector(selector) as HTMLElement | T | null
5
10
  }
6
11
 
12
+ /**
13
+ * # Move
14
+ * Helper function that can move a node inside another node.
15
+ * @param {Node} source The node to be moved.
16
+ * @param {Node} destination The destination node.
17
+ * @param {boolean} asFirstChild Append or prepend the new node inside the child list.
18
+ */
7
19
  export function move(source: Node, destination: Node, asFirstChild: boolean = false): void
8
20
  {
9
21
  if (source && destination) {
@@ -13,8 +25,19 @@ export function move(source: Node, destination: Node, asFirstChild: boolean = fa
13
25
  }
14
26
  }
15
27
 
28
+ /**
29
+ * # Make
30
+ * Short hand helper function that creates Nodes.
31
+ * @param {ElementTag} tag
32
+ */
16
33
  export const mk = (tag: ElementTag) => document.createElement(tag)
17
34
 
35
+ /**
36
+ * # Add Class
37
+ * Helper class that easily adds classes to an element.
38
+ * @param {HTMLElement} node The node
39
+ * @param {...string[]} classes
40
+ */
18
41
  export function addClass(node: HTMLElement, ...classes: string[]): void
19
42
  {
20
43
  node.classList.add(...classes)
package/src/main.ts CHANGED
@@ -1,8 +1,5 @@
1
- import {Nanosplash} from "./Core/Nanosplash";
2
- import {NanosplashOptions} from "./types";
1
+ import Nanosplash from "./Core/Nanosplash";
3
2
  window.addEventListener('load', () => {
4
3
  window.Nanosplash = Nanosplash
5
- window.installNanosplash = (options?: NanosplashOptions) => {
6
- window.ns = new Nanosplash(options)
7
- }
4
+ window.ns = new Nanosplash()
8
5
  })