vaderjs 1.1.7 → 1.1.9
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/.vscode/vaderjs.autosense.json +5 -0
- package/index.js +1 -1
- package/package.json +2 -2
- package/vader.js +411 -95
- package/vaderRouter.js +55 -62
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vaderjs",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "A Reactive Framework for Single-Page Applications (SPA)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"bugs": {
|
|
23
23
|
"url": "https://github.com/Postr-Inc/Vader.js/issues"
|
|
24
24
|
},
|
|
25
|
-
"homepage": "https://
|
|
25
|
+
"homepage": "https://vader-js.pages.dev",
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"typescript": "^5.2.2"
|
|
28
28
|
}
|
package/vader.js
CHANGED
|
@@ -1,55 +1,39 @@
|
|
|
1
|
-
|
|
2
1
|
let dom = /**@type {Obect} **/ {};
|
|
3
2
|
/**
|
|
4
3
|
* @function useRef
|
|
5
4
|
* @description Allows you to get reference to DOM element
|
|
6
5
|
* @param {String} ref
|
|
7
|
-
* @returns {Object} {current}
|
|
6
|
+
* @returns {void | Object} {current, update}
|
|
8
7
|
*/
|
|
9
|
-
export const useRef = (ref
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
let el = dom[ref] || document.querySelector(`[ref="${ref}"]`);
|
|
8
|
+
export const useRef = (ref) => {
|
|
9
|
+
const element = document.querySelector(`[ref="${ref}"]`);
|
|
10
|
+
const getElement = () => element;
|
|
13
11
|
|
|
14
|
-
// Function to update the DOM element with new HTML content
|
|
15
|
-
/**
|
|
16
|
-
* @function update
|
|
17
|
-
* @description Allows you to update the DOM element with new HTML content
|
|
18
|
-
* @param {String} data
|
|
19
|
-
*/
|
|
20
12
|
const update = (data) => {
|
|
21
|
-
// Parse the new HTML data
|
|
22
13
|
const newDom = new DOMParser().parseFromString(data, "text/html");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const newHtml = newDom.body.firstChild;
|
|
14
|
+
const newElement = newDom.body.firstChild;
|
|
26
15
|
|
|
27
|
-
if (
|
|
28
|
-
//
|
|
29
|
-
const isDifferent = !
|
|
16
|
+
if (element) {
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
const isDifferent = !newElement.isEqualNode(element);
|
|
30
19
|
if (isDifferent) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
el.parentNode.replaceChild(newElement, el);
|
|
34
|
-
dom[ref] = newElement;
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
element.parentNode.replaceChild(newElement, element);
|
|
35
22
|
}
|
|
36
|
-
} else {
|
|
37
|
-
// If the element doesn't exist, create it
|
|
38
|
-
el = newHtml.cloneNode(true);
|
|
39
|
-
dom[ref] = el;
|
|
40
23
|
}
|
|
41
24
|
};
|
|
42
25
|
|
|
43
26
|
return {
|
|
44
|
-
current:
|
|
27
|
+
current: getElement(),
|
|
45
28
|
update,
|
|
46
29
|
};
|
|
47
30
|
};
|
|
31
|
+
|
|
48
32
|
let components = [];
|
|
49
33
|
/**
|
|
50
34
|
* @class Component
|
|
51
35
|
* @description Allows you to create a component
|
|
52
|
-
* @returns {
|
|
36
|
+
* @returns {void}
|
|
53
37
|
* @example
|
|
54
38
|
* import { Vader } from "../../dist/vader/index.js";
|
|
55
39
|
* export class Home extends Vader.Component {
|
|
@@ -70,7 +54,6 @@ export class Component {
|
|
|
70
54
|
this.states = {};
|
|
71
55
|
//@ts-ignore
|
|
72
56
|
this.name = this.constructor.name;
|
|
73
|
-
console.log(this.name);
|
|
74
57
|
this.executedEffects = {};
|
|
75
58
|
this.storedProps = {};
|
|
76
59
|
this.componentMounted = false;
|
|
@@ -80,8 +63,8 @@ export class Component {
|
|
|
80
63
|
* @property {Array} $_signal_subscribers_ran
|
|
81
64
|
* @description Allows you to keep track of signal subscribers
|
|
82
65
|
* @private
|
|
83
|
-
|
|
84
|
-
this.$_signal_subscribers_ran =
|
|
66
|
+
*/
|
|
67
|
+
this.$_signal_subscribers_ran = [];
|
|
85
68
|
this.effects = {};
|
|
86
69
|
this.$_useStore_subscribers = [];
|
|
87
70
|
this.init();
|
|
@@ -92,42 +75,22 @@ export class Component {
|
|
|
92
75
|
state: null,
|
|
93
76
|
},
|
|
94
77
|
});
|
|
78
|
+
this.snapshots = [];
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
init() {
|
|
98
|
-
//@ts-ignore
|
|
99
82
|
this.registerComponent();
|
|
100
|
-
//@ts-ignore
|
|
101
|
-
window.states = this.states;
|
|
102
|
-
//@ts-ignore
|
|
103
|
-
window.useState = this.useState;
|
|
104
|
-
//@ts-ignore
|
|
105
|
-
window.setState = this.setState;
|
|
106
|
-
//@ts-ignore
|
|
107
|
-
window.useEffect = this.useEffect;
|
|
108
|
-
//@ts-ignore
|
|
109
|
-
window.useAuth = this.useAuth;
|
|
110
|
-
//@ts-ignore
|
|
111
|
-
window.useSyncStore = this.useSyncStore;
|
|
112
|
-
//@ts-ignore
|
|
113
|
-
window.useReducer = this.useReducer;
|
|
114
|
-
//@ts-ignore
|
|
115
|
-
window.runEffects = this.runEffects;
|
|
116
|
-
//@ts-ignore
|
|
117
|
-
window.rf = this.rf;
|
|
118
|
-
//@ts-ignore
|
|
119
|
-
window.signal = this.signal;
|
|
120
83
|
}
|
|
121
84
|
|
|
122
85
|
registerComponent() {
|
|
123
86
|
components.push(this);
|
|
124
87
|
}
|
|
125
|
-
|
|
88
|
+
|
|
126
89
|
/**
|
|
127
90
|
* @method setState
|
|
128
91
|
* @description Allows you to set state
|
|
129
92
|
* @param {String} key
|
|
130
|
-
* @param {*} value
|
|
93
|
+
* @param {*} value
|
|
131
94
|
* @returns {void}
|
|
132
95
|
* @example
|
|
133
96
|
* this.setState('count', 1)
|
|
@@ -136,13 +99,51 @@ export class Component {
|
|
|
136
99
|
this.states[key] = value;
|
|
137
100
|
this.updateComponent();
|
|
138
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* @method componentUnmount
|
|
104
|
+
* @description Allows you to run code after component has unmounted
|
|
105
|
+
* @type {VoidFunction}
|
|
106
|
+
* @returns {void}
|
|
107
|
+
*/
|
|
108
|
+
unmount() {
|
|
109
|
+
this.componentMounted = false;
|
|
110
|
+
this.componentWillUnmount();
|
|
111
|
+
// @ts-ignore
|
|
112
|
+
document.querySelector(`[data-component="${this.name}"]`).remove();
|
|
113
|
+
if (!document.querySelector(`[data-component="${this.name}"]`)) {
|
|
114
|
+
components = components.filter(
|
|
115
|
+
(component) => component.name !== this.name
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
139
119
|
|
|
140
|
-
|
|
120
|
+
/**
|
|
121
|
+
* @method componentUpdate
|
|
122
|
+
* @description Allows you to run code after component has updated
|
|
123
|
+
* @param {Object} prev_state
|
|
124
|
+
* @param {Object} prev_props
|
|
125
|
+
* @param {Object} snapshot
|
|
126
|
+
* @returns {void}
|
|
127
|
+
* @example
|
|
128
|
+
* componentUpdate(prev_state, prev_props, snapshot) {
|
|
129
|
+
* console.log(prev_state, prev_props, snapshot)
|
|
130
|
+
* }
|
|
131
|
+
* */
|
|
132
|
+
componentUpdate(prev_state, prev_props, snapshot) {}
|
|
141
133
|
/**
|
|
142
134
|
* @method componentDidMount
|
|
143
135
|
* @description Allows you to run code after component has mounted
|
|
144
136
|
*/
|
|
145
137
|
componentDidMount() {}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @method componentWillUnmount
|
|
141
|
+
* @description Allows you to run code before component unmounts
|
|
142
|
+
* @type {VoidFunction}
|
|
143
|
+
* @returns {void}
|
|
144
|
+
*/
|
|
145
|
+
componentWillUnmount() {}
|
|
146
|
+
|
|
146
147
|
/**
|
|
147
148
|
* @method signal
|
|
148
149
|
* @description Allows you to create a signal
|
|
@@ -227,6 +228,7 @@ export class Component {
|
|
|
227
228
|
};
|
|
228
229
|
this.$_signal_call = () => {
|
|
229
230
|
hasCaller = true;
|
|
231
|
+
// @ts-ignore
|
|
230
232
|
this.$_signal_dispatch();
|
|
231
233
|
};
|
|
232
234
|
/**
|
|
@@ -305,8 +307,8 @@ export class Component {
|
|
|
305
307
|
* auth.can('create') // true
|
|
306
308
|
*/
|
|
307
309
|
useAuth(options) {
|
|
308
|
-
/**@type {Array}**/
|
|
309
|
-
let rules =
|
|
310
|
+
/**@type {Array}**/
|
|
311
|
+
let rules = options.rulesets;
|
|
310
312
|
if (!rules) {
|
|
311
313
|
throw new Error("No rulesets provided");
|
|
312
314
|
}
|
|
@@ -336,8 +338,8 @@ export class Component {
|
|
|
336
338
|
/**
|
|
337
339
|
* @function canWithRole
|
|
338
340
|
* @param {String} action
|
|
339
|
-
* @param {String} role
|
|
340
|
-
* @returns
|
|
341
|
+
* @param {String} role
|
|
342
|
+
* @returns
|
|
341
343
|
*/
|
|
342
344
|
canWithRole: (action, role) => {
|
|
343
345
|
return auth.can(action) && auth.hasRole(role);
|
|
@@ -388,12 +390,22 @@ export class Component {
|
|
|
388
390
|
* setCount({type: 'increment'})
|
|
389
391
|
*/
|
|
390
392
|
useReducer(key, reducer, initialState) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
393
|
+
if (!this.states[key]) {
|
|
394
|
+
this.states[key] = initialState;
|
|
395
|
+
}
|
|
396
|
+
return [
|
|
397
|
+
this.states[key],
|
|
398
|
+
/**
|
|
399
|
+
* @function dispatch
|
|
400
|
+
* @description Allows you to dispatch a reducer
|
|
401
|
+
* @param {*} action
|
|
402
|
+
* @returns {void}
|
|
403
|
+
*/
|
|
404
|
+
(action) => {
|
|
405
|
+
this.states[key] = reducer(this.states[key], action);
|
|
406
|
+
this.updateComponent();
|
|
407
|
+
},
|
|
408
|
+
];
|
|
397
409
|
}
|
|
398
410
|
runEffects() {
|
|
399
411
|
Object.keys(this.effects).forEach((component) => {
|
|
@@ -408,28 +420,28 @@ export class Component {
|
|
|
408
420
|
/**
|
|
409
421
|
* @method useSyncStore
|
|
410
422
|
* @description Allows you to create a store
|
|
411
|
-
* @param {
|
|
412
|
-
* @param {*} initialState
|
|
423
|
+
* @param {String} storeName
|
|
424
|
+
* @param {*} initialState
|
|
413
425
|
* @returns {Object} {getField, setField, subscribe, clear}
|
|
414
426
|
* @example
|
|
415
427
|
* let store = this.useSyncStore('store', {count: 0})
|
|
416
428
|
* store.setField('count', 1)
|
|
417
429
|
* store.getField('count') // 1
|
|
418
|
-
*
|
|
430
|
+
*
|
|
419
431
|
*/
|
|
420
432
|
useSyncStore(storeName, initialState) {
|
|
421
433
|
let [storedState, setStoredState] = this.useState(
|
|
422
434
|
storeName,
|
|
423
435
|
initialState ||
|
|
424
|
-
|
|
436
|
+
// @ts-ignore
|
|
425
437
|
localStorage.getItem(`$_vader_${storeName}`, (s) => {
|
|
426
|
-
|
|
427
438
|
localStorage.setItem(`$_vader_${storeName}`, JSON.stringify(s));
|
|
428
439
|
this.$_useStore_subscribers.forEach((subscriber) => {
|
|
429
440
|
subscriber(s);
|
|
430
441
|
});
|
|
431
442
|
}) ||
|
|
432
|
-
{}
|
|
443
|
+
{},
|
|
444
|
+
() => {}
|
|
433
445
|
);
|
|
434
446
|
|
|
435
447
|
const getField = (fieldName) => {
|
|
@@ -460,7 +472,7 @@ export class Component {
|
|
|
460
472
|
* @description Allows you to create a state
|
|
461
473
|
* @param {String} key
|
|
462
474
|
* @param {*} initialValue
|
|
463
|
-
* @param {
|
|
475
|
+
* @param {Function} callback
|
|
464
476
|
* @url - useState works similarly to - https://react.dev/reference/react/useState
|
|
465
477
|
* @returns {Array} [state, setState]
|
|
466
478
|
* @example
|
|
@@ -476,6 +488,12 @@ export class Component {
|
|
|
476
488
|
}
|
|
477
489
|
return [
|
|
478
490
|
this.states[key],
|
|
491
|
+
/**
|
|
492
|
+
* @function setState
|
|
493
|
+
* @description Allows you to set state
|
|
494
|
+
* @param {*} value
|
|
495
|
+
* @returns {void}
|
|
496
|
+
*/
|
|
479
497
|
(value) => {
|
|
480
498
|
this.states[key] = value;
|
|
481
499
|
this.updateComponent();
|
|
@@ -511,13 +529,13 @@ export class Component {
|
|
|
511
529
|
this.hasMounted = true;
|
|
512
530
|
}
|
|
513
531
|
|
|
514
|
-
return{
|
|
532
|
+
return {
|
|
515
533
|
cleanup: () => {
|
|
516
534
|
this.effects[this.name] = this.effects[this.name].filter(
|
|
517
535
|
(effect) => effect !== effectFn
|
|
518
536
|
);
|
|
519
537
|
},
|
|
520
|
-
}
|
|
538
|
+
};
|
|
521
539
|
}
|
|
522
540
|
/**
|
|
523
541
|
* @method $Function
|
|
@@ -536,7 +554,7 @@ export class Component {
|
|
|
536
554
|
}
|
|
537
555
|
let name = fn.name;
|
|
538
556
|
if (!name) {
|
|
539
|
-
name = "anonymous";
|
|
557
|
+
name = "anonymous" + Math.floor(Math.random() * 100000000000000000);
|
|
540
558
|
}
|
|
541
559
|
window[name] = fn;
|
|
542
560
|
// @ts-ignore
|
|
@@ -546,12 +564,29 @@ export class Component {
|
|
|
546
564
|
// Add other methods like render, useEffect, useReducer, useAuth, etc.
|
|
547
565
|
|
|
548
566
|
updateComponent() {
|
|
567
|
+
const fragment = document.createDocumentFragment();
|
|
549
568
|
Object.keys(components).forEach(async (component) => {
|
|
550
569
|
const { name } = components[component];
|
|
551
570
|
const componentContainer = document.querySelector(
|
|
552
571
|
`[data-component="${name}"]`
|
|
553
572
|
);
|
|
554
573
|
|
|
574
|
+
let time = new Date().getTime().toLocaleString();
|
|
575
|
+
/**
|
|
576
|
+
* @property {Object} snapshot
|
|
577
|
+
* @description Allows you to keep track of component snapshots
|
|
578
|
+
* @private
|
|
579
|
+
* @returns {Object} {name, time, prev_state, prev_props, content}
|
|
580
|
+
*/
|
|
581
|
+
let snapshot = {
|
|
582
|
+
name: name,
|
|
583
|
+
time: time,
|
|
584
|
+
prev_state: this.states,
|
|
585
|
+
prev_props: this.storedProps,
|
|
586
|
+
// @ts-ignore
|
|
587
|
+
content: componentContainer.innerHTML,
|
|
588
|
+
};
|
|
589
|
+
|
|
555
590
|
if (!componentContainer) return;
|
|
556
591
|
const newHtml = await new Function(
|
|
557
592
|
"useState",
|
|
@@ -573,14 +608,106 @@ export class Component {
|
|
|
573
608
|
this.signal,
|
|
574
609
|
this.render
|
|
575
610
|
);
|
|
576
|
-
this.componentDidMount();
|
|
577
611
|
|
|
578
|
-
if (newHtml
|
|
579
|
-
|
|
612
|
+
if (newHtml !== componentContainer.innerHTML) {
|
|
613
|
+
if (this.snapshots.length > 0) {
|
|
614
|
+
let lastSnapshot = this.snapshots[this.snapshots.length - 1];
|
|
615
|
+
if (lastSnapshot !== snapshot) {
|
|
616
|
+
this.snapshots.push(snapshot);
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
this.snapshots.push(snapshot);
|
|
620
|
+
}
|
|
621
|
+
this.componentUpdate(
|
|
622
|
+
snapshot.prev_state,
|
|
623
|
+
snapshot.prev_props,
|
|
624
|
+
snapshot.content
|
|
625
|
+
);
|
|
626
|
+
// batch updates
|
|
627
|
+
fragment.appendChild(
|
|
628
|
+
document.createRange().createContextualFragment(newHtml)
|
|
629
|
+
);
|
|
630
|
+
componentContainer.innerHTML = "";
|
|
631
|
+
componentContainer.appendChild(fragment);
|
|
632
|
+
this.runEffects();
|
|
580
633
|
}
|
|
581
634
|
});
|
|
582
635
|
}
|
|
636
|
+
/**
|
|
637
|
+
* @method validateClassName
|
|
638
|
+
* @param {String} className
|
|
639
|
+
* @private
|
|
640
|
+
* @returns {Boolean}
|
|
641
|
+
*/
|
|
642
|
+
validateClassName(className) {
|
|
643
|
+
// validate classNames ensure they are camelCase but also allow for - and _
|
|
644
|
+
return /^[a-zA-Z0-9-_]+$/.test(className);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* The `html` method generates and processes HTML content for a component, performing various validations and tasks.
|
|
649
|
+
*
|
|
650
|
+
* @param {String} strings - The HTML content to be processed.
|
|
651
|
+
* @param {...any} args - Dynamic values to be inserted into the template.
|
|
652
|
+
* @returns {string} - The processed HTML content as a string.
|
|
653
|
+
*
|
|
654
|
+
* @throws {SyntaxError} - Throws a `SyntaxError` if image-related attributes are missing or invalid.
|
|
655
|
+
* @throws {Error} - Throws an `Error` if there are issues with class names or relative paths.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* // Example usage within a component:
|
|
659
|
+
* const myComponent = new Component();
|
|
660
|
+
* const htmlContent = myComponent.html`
|
|
661
|
+
* <div>
|
|
662
|
+
* <img src="/images/example.jpg" alt="Example Image" />
|
|
663
|
+
* </div>
|
|
664
|
+
* `;
|
|
665
|
+
* document.body.innerHTML = htmlContent;
|
|
666
|
+
*
|
|
667
|
+
* @remarks
|
|
668
|
+
* The `html` method is a core function used in component rendering. It allows you to define and generate HTML content within your component while enforcing best practices and accessibility standards. The method performs several essential tasks:
|
|
669
|
+
*
|
|
670
|
+
* 1. **Image Validation**: It checks images for the presence of 'alt' attributes and their validity.
|
|
671
|
+
* - Throws a `SyntaxError` if an image is missing the 'alt' attribute.
|
|
672
|
+
* - Throws a `SyntaxError` if the 'alt' attribute is empty.
|
|
673
|
+
* - Checks for an 'aria-hidden' attribute for image elements.
|
|
674
|
+
*
|
|
675
|
+
* 2. **Class Attribute Handling**: It enforces class attribute usage and allows optional configuration via comments.
|
|
676
|
+
* - Throws an `Error` if 'class' attributes are used without permission.
|
|
677
|
+
* - Supports 'className' attributes for class definitions.
|
|
678
|
+
* - Allows or disallows class-related comments based on your configuration.
|
|
679
|
+
*
|
|
680
|
+
* 3. **Relative Path Handling**: It processes relative paths in 'href' and 'src' attributes, ensuring proper routing.
|
|
681
|
+
* - Converts relative 'href' attributes to anchor links with appropriate routing.
|
|
682
|
+
* - Converts relative 'src' attributes to absolute paths with 'public' directories.
|
|
683
|
+
*
|
|
684
|
+
* 4. **Custom Component Attributes**: It supports adding a 'data-component' attribute to the root element.
|
|
685
|
+
* - Ensures that the 'data-component' attribute is present for component identification.
|
|
686
|
+
*
|
|
687
|
+
* 5. **Lifecycle Method Invocation**: It invokes the `componentDidMount` method if called from a 'render' context.
|
|
688
|
+
* - Executes `componentDidMount` to handle component initialization once the DOM is ready.
|
|
689
|
+
*
|
|
690
|
+
* @see {@link Component}
|
|
691
|
+
* @see {@link Component#componentDidMount}
|
|
692
|
+
*/
|
|
583
693
|
html(strings, ...args) {
|
|
694
|
+
// @ts-ignore
|
|
695
|
+
if (
|
|
696
|
+
// @ts-ignore
|
|
697
|
+
new Error().stack &&
|
|
698
|
+
// @ts-ignore
|
|
699
|
+
new Error().stack.split("\n").length > 0 &&
|
|
700
|
+
// @ts-ignore
|
|
701
|
+
new Error().stack.split("\n")[2] &&
|
|
702
|
+
// @ts-ignore
|
|
703
|
+
new Error().stack.split("\n")[2].includes("render") &&
|
|
704
|
+
!this.componentMounted
|
|
705
|
+
) {
|
|
706
|
+
this.componentMounted = true;
|
|
707
|
+
this.componentDidMount();
|
|
708
|
+
console.log("component mounted");
|
|
709
|
+
}
|
|
710
|
+
|
|
584
711
|
let result = "";
|
|
585
712
|
for (let i = 0; i < strings.length; i++) {
|
|
586
713
|
result += strings[i];
|
|
@@ -588,26 +715,175 @@ export class Component {
|
|
|
588
715
|
result += args[i];
|
|
589
716
|
}
|
|
590
717
|
}
|
|
591
|
-
|
|
718
|
+
|
|
719
|
+
if (!result.trim().startsWith("<body>")) {
|
|
720
|
+
console.warn(
|
|
721
|
+
"You should wrap your html in a body tag, vader may not grab all html!"
|
|
722
|
+
);
|
|
723
|
+
}
|
|
592
724
|
let dom = new DOMParser().parseFromString(result, "text/html");
|
|
593
725
|
let elements = dom.body.querySelectorAll("*");
|
|
726
|
+
|
|
594
727
|
elements.forEach((element) => {
|
|
595
|
-
|
|
596
|
-
|
|
728
|
+
switch (element.nodeName) {
|
|
729
|
+
case "IMG":
|
|
730
|
+
if (
|
|
731
|
+
!element.hasAttribute("alt") &&
|
|
732
|
+
!document.documentElement.outerHTML
|
|
733
|
+
.trim()
|
|
734
|
+
.includes("<!-- #vader-disable_accessibility -->")
|
|
735
|
+
) {
|
|
736
|
+
throw new SyntaxError(
|
|
737
|
+
`Image: ${element.outerHTML} missing alt attribute`
|
|
738
|
+
);
|
|
739
|
+
} else if (
|
|
740
|
+
element.hasAttribute("alt") &&
|
|
741
|
+
// @ts-ignore
|
|
742
|
+
element.getAttribute("alt").length < 1 &&
|
|
743
|
+
!document.documentElement.outerHTML
|
|
744
|
+
.trim()
|
|
745
|
+
.includes("<!-- #vader-disable_accessibility -->")
|
|
746
|
+
) {
|
|
747
|
+
throw new SyntaxError(
|
|
748
|
+
`Image: ${element.outerHTML} alt attribute cannot be empty`
|
|
749
|
+
);
|
|
750
|
+
} else if (
|
|
751
|
+
element.hasAttribute("src") &&
|
|
752
|
+
!document.documentElement.outerHTML
|
|
753
|
+
.trim()
|
|
754
|
+
.includes("<!-- #vader-disable_accessibility -->")
|
|
755
|
+
) {
|
|
756
|
+
let prevurl = element.getAttribute("src");
|
|
757
|
+
element.setAttribute("aria-hidden", "true");
|
|
758
|
+
element.setAttribute("hidden", "true");
|
|
759
|
+
let url =
|
|
760
|
+
window.location.origin +
|
|
761
|
+
window.location.pathname +
|
|
762
|
+
"/public/" +
|
|
763
|
+
element.getAttribute("src");
|
|
764
|
+
let image = new Image();
|
|
765
|
+
image.src = url;
|
|
766
|
+
image.onerror = () => {
|
|
767
|
+
// @ts-ignore
|
|
768
|
+
element.setAttribute("src", prevurl);
|
|
769
|
+
throw new Error(`Image: ${element.outerHTML} not found`);
|
|
770
|
+
};
|
|
771
|
+
element.setAttribute("src", url);
|
|
772
|
+
|
|
773
|
+
image.onload = () => {
|
|
774
|
+
document.querySelectorAll(`img[src="${url}"]`).forEach((img) => {
|
|
775
|
+
img.setAttribute("src", url);
|
|
776
|
+
img.removeAttribute("aria-hidden");
|
|
777
|
+
img.removeAttribute("hidden");
|
|
778
|
+
});
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
break;
|
|
782
|
+
|
|
783
|
+
default:
|
|
784
|
+
if (element.hasAttribute("ref")) {
|
|
785
|
+
// @ts-ignore
|
|
786
|
+
dom[element.getAttribute("ref")] = element;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (element.hasAttribute("class")) {
|
|
790
|
+
const allowClassComments =
|
|
791
|
+
document.documentElement.outerHTML.includes(
|
|
792
|
+
"<!-- #vader-allow_class -->"
|
|
793
|
+
);
|
|
794
|
+
if (!allowClassComments) {
|
|
795
|
+
console.warn(
|
|
796
|
+
"you can disable class errors using, <!-- #vader-allow_class -->"
|
|
797
|
+
);
|
|
798
|
+
throw new Error(
|
|
799
|
+
"class attribute is not allowed, please use className instead"
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
} else if (element.hasAttribute("className")) {
|
|
803
|
+
const isLocalhost = window.location.href.includes("localhost");
|
|
804
|
+
const is127001 = window.location.href.includes("127.0.0.1");
|
|
805
|
+
const ignoreClassComments = document.documentElement.outerHTML
|
|
806
|
+
.trim()
|
|
807
|
+
.includes("<!-- #vader-class-ignore -->");
|
|
808
|
+
const allowClassComments = document.documentElement.outerHTML
|
|
809
|
+
.trim()
|
|
810
|
+
.includes("<!-- #vader-allow_class -->");
|
|
811
|
+
|
|
812
|
+
if (
|
|
813
|
+
// @ts-ignore
|
|
814
|
+
(!this.validateClassName(element.getAttribute("className")) &&
|
|
815
|
+
isLocalhost) ||
|
|
816
|
+
(is127001 && !ignoreClassComments && !allowClassComments)
|
|
817
|
+
) {
|
|
818
|
+
throw new Error(
|
|
819
|
+
`Invalid className ${element.getAttribute(
|
|
820
|
+
"className"
|
|
821
|
+
)}, please use camelCase instead - example: myClass`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
// @ts-ignore
|
|
825
|
+
element.setAttribute("class", element.getAttribute("className"));
|
|
826
|
+
element.removeAttribute("className");
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (
|
|
830
|
+
element.hasAttribute("href") &&
|
|
831
|
+
// @ts-ignore
|
|
832
|
+
element.getAttribute("href").startsWith("/") &&
|
|
833
|
+
!document.documentElement.outerHTML
|
|
834
|
+
.trim()
|
|
835
|
+
.includes("<!-- #vader-disable_relative-paths -->")
|
|
836
|
+
) {
|
|
837
|
+
element.setAttribute(
|
|
838
|
+
"href",
|
|
839
|
+
// @ts-ignore
|
|
840
|
+
`#/${element.getAttribute("href").replace("/", "")}`
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
if (
|
|
845
|
+
element.hasAttribute("src") &&
|
|
846
|
+
// @ts-ignore
|
|
847
|
+
element.getAttribute("src").startsWith("/") &&
|
|
848
|
+
!document.documentElement.outerHTML
|
|
849
|
+
.trim()
|
|
850
|
+
.includes("<!-- #vader-disable_relative-paths -->")
|
|
851
|
+
) {
|
|
852
|
+
element.setAttribute(
|
|
853
|
+
"src",
|
|
854
|
+
`${window.location.origin}/public${element.getAttribute("src")}`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
break;
|
|
597
858
|
}
|
|
598
859
|
});
|
|
860
|
+
|
|
861
|
+
result = dom.body.innerHTML;
|
|
862
|
+
|
|
599
863
|
this.Componentcontent = result;
|
|
864
|
+
|
|
600
865
|
if (!result.includes("<div data-component")) {
|
|
601
|
-
result = `<div
|
|
866
|
+
result = `<div
|
|
867
|
+
|
|
868
|
+
data-component="${this.name}">${result}</div>`;
|
|
602
869
|
}
|
|
603
870
|
|
|
604
871
|
return result;
|
|
605
872
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
873
|
+
// write types to ensure it returns a string
|
|
874
|
+
/**
|
|
875
|
+
* @method render
|
|
876
|
+
* @description Allows you to render html
|
|
877
|
+
* @returns {Promise <any>}
|
|
878
|
+
* @example
|
|
879
|
+
* async render() {
|
|
880
|
+
* return this.html(`
|
|
881
|
+
* <div className="hero p-5">
|
|
882
|
+
* <h1>Home</h1>
|
|
883
|
+
* </div>
|
|
884
|
+
* `);
|
|
885
|
+
*/
|
|
886
|
+
async render() {}
|
|
611
887
|
}
|
|
612
888
|
|
|
613
889
|
/**
|
|
@@ -629,12 +905,32 @@ export class Component {
|
|
|
629
905
|
* `);
|
|
630
906
|
* }
|
|
631
907
|
*/
|
|
632
|
-
|
|
908
|
+
const Vader = {
|
|
909
|
+
/**
|
|
910
|
+
* @class Component
|
|
911
|
+
* @description Allows you to create a component
|
|
912
|
+
* @returns {void}
|
|
913
|
+
* @memberof {Vader}
|
|
914
|
+
* @example
|
|
915
|
+
* import { Vader } from "../../dist/vader/index.js";
|
|
916
|
+
* export class Home extends Vader.Component {
|
|
917
|
+
* constructor() {
|
|
918
|
+
* super();
|
|
919
|
+
* }
|
|
920
|
+
* async render() {
|
|
921
|
+
* return this.html(`
|
|
922
|
+
* <div className="hero p-5">
|
|
923
|
+
* <h1>Home</h1>
|
|
924
|
+
* </div>
|
|
925
|
+
* `);
|
|
926
|
+
* }
|
|
927
|
+
* }
|
|
928
|
+
*/
|
|
633
929
|
Component: Component,
|
|
634
930
|
useRef: useRef,
|
|
635
931
|
};
|
|
636
932
|
export const component = (name) => {
|
|
637
|
-
return new Component()
|
|
933
|
+
return new Component();
|
|
638
934
|
};
|
|
639
935
|
|
|
640
936
|
/**
|
|
@@ -652,12 +948,20 @@ let cache = {};
|
|
|
652
948
|
/**
|
|
653
949
|
* @function include
|
|
654
950
|
* @description Allows you to include html file
|
|
655
|
-
* @returns
|
|
951
|
+
* @returns {Promise} - modified string with html content
|
|
656
952
|
* @param {string} path
|
|
657
|
-
* @param {Object} options
|
|
658
953
|
*/
|
|
659
954
|
|
|
660
|
-
export const include = (path
|
|
955
|
+
export const include = async (path) => {
|
|
956
|
+
if (
|
|
957
|
+
path.startsWith("/") &&
|
|
958
|
+
!path.includes("/src/") &&
|
|
959
|
+
!document.documentElement.outerHTML
|
|
960
|
+
.trim()
|
|
961
|
+
.includes("<!-- #vader-disable_relative-paths -->")
|
|
962
|
+
) {
|
|
963
|
+
path = "/src/" + path;
|
|
964
|
+
}
|
|
661
965
|
if (cache[path]) {
|
|
662
966
|
return new Function(`return \`${cache[path]}\`;`)();
|
|
663
967
|
}
|
|
@@ -669,13 +973,23 @@ export const include = (path, options) => {
|
|
|
669
973
|
}
|
|
670
974
|
return res.text();
|
|
671
975
|
})
|
|
672
|
-
.then((data) => {
|
|
976
|
+
.then(async (data) => {
|
|
673
977
|
// Handle includes
|
|
674
978
|
let includes = data.match(/<include src="(.*)"\/>/gs);
|
|
675
979
|
if (includes) {
|
|
676
980
|
// Use Promise.all to fetch all includes concurrently
|
|
677
981
|
const includePromises = includes.map((e) => {
|
|
982
|
+
// @ts-ignore
|
|
678
983
|
let includePath = e.match(/<include src="(.*)"\/>/)[1];
|
|
984
|
+
|
|
985
|
+
if (
|
|
986
|
+
includePath.startsWith("/") &&
|
|
987
|
+
!document.documentElement.outerHTML
|
|
988
|
+
.trim()
|
|
989
|
+
.includes("<!-- #vader-disable_relative-paths -->")
|
|
990
|
+
) {
|
|
991
|
+
includePath = "/src" + includePath;
|
|
992
|
+
}
|
|
679
993
|
return include(includePath).then((includeData) => {
|
|
680
994
|
// Replace the include tag with the fetched data
|
|
681
995
|
data = data.replace(e, includeData);
|
|
@@ -692,4 +1006,6 @@ export const include = (path, options) => {
|
|
|
692
1006
|
return new Function(`return \`${data}\`;`)();
|
|
693
1007
|
}
|
|
694
1008
|
});
|
|
695
|
-
};
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
export default Vader;
|
package/vaderRouter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
window.$URL_PARAMS = {};
|
|
3
|
-
// @ts-ignore
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
window.$URL_PARAMS = {};
|
|
3
|
+
// @ts-ignore
|
|
4
4
|
window.$URL_QUERY = {};
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -31,6 +31,7 @@ class VaderRouter {
|
|
|
31
31
|
* Listener function for hash change events.
|
|
32
32
|
* @type {Function}
|
|
33
33
|
*/
|
|
34
|
+
//@ts-ignore
|
|
34
35
|
this.hashChangeListener = null;
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -43,6 +44,7 @@ class VaderRouter {
|
|
|
43
44
|
* Flag indicating if custom error handling is enabled.
|
|
44
45
|
* @type {boolean}
|
|
45
46
|
*/
|
|
47
|
+
//@ts-ignore
|
|
46
48
|
this.customerror = null;
|
|
47
49
|
|
|
48
50
|
/**
|
|
@@ -95,8 +97,9 @@ class VaderRouter {
|
|
|
95
97
|
this.customerror = true;
|
|
96
98
|
}
|
|
97
99
|
handleRoute(method) {
|
|
100
|
+
|
|
98
101
|
let route = window.location.hash.substring(1);
|
|
99
|
-
|
|
102
|
+
// @ts-ignore
|
|
100
103
|
window.$CURRENT_URL = route;
|
|
101
104
|
|
|
102
105
|
// remove query params from route
|
|
@@ -105,11 +108,12 @@ class VaderRouter {
|
|
|
105
108
|
}
|
|
106
109
|
route = route.split("/")[0] + "/" + route.split("/")[1];
|
|
107
110
|
if (this.routes[route]) {
|
|
111
|
+
|
|
108
112
|
this.storedroutes.push(route);
|
|
109
113
|
const req = {
|
|
110
|
-
|
|
114
|
+
// @ts-ignore
|
|
111
115
|
params: $URL_PARAMS ? $URL_PARAMS : {},
|
|
112
|
-
|
|
116
|
+
// @ts-ignore
|
|
113
117
|
query: $URL_QUERY ? $URL_QUERY : {},
|
|
114
118
|
url: route,
|
|
115
119
|
method: method ? method : "GET",
|
|
@@ -122,16 +126,19 @@ class VaderRouter {
|
|
|
122
126
|
document.querySelector(selector).innerHTML = data;
|
|
123
127
|
},
|
|
124
128
|
};
|
|
125
|
-
if
|
|
129
|
+
if(typeof this.routes[route] === 'function'){
|
|
126
130
|
this.routes[route](req, res);
|
|
127
131
|
}
|
|
128
132
|
} else {
|
|
129
133
|
if (this.customerror) {
|
|
134
|
+
//@ts-ignore
|
|
130
135
|
this.handleError("404", route);
|
|
131
136
|
console.error("404: Route not found");
|
|
132
137
|
} else {
|
|
133
138
|
console.error("404: Route not found");
|
|
134
139
|
}
|
|
140
|
+
|
|
141
|
+
|
|
135
142
|
}
|
|
136
143
|
}
|
|
137
144
|
/**
|
|
@@ -143,7 +150,7 @@ class VaderRouter {
|
|
|
143
150
|
* @description used by start() to handle errors.
|
|
144
151
|
*/
|
|
145
152
|
|
|
146
|
-
handleError(type, data
|
|
153
|
+
handleError(type, data) {
|
|
147
154
|
if (this.errorHandlers[type]) {
|
|
148
155
|
this.errorHandlers[type](data);
|
|
149
156
|
} else {
|
|
@@ -187,19 +194,17 @@ class VaderRouter {
|
|
|
187
194
|
const params = {};
|
|
188
195
|
|
|
189
196
|
for (let i = 0; i < paramNames.length; i++) {
|
|
197
|
+
//@ts-ignore
|
|
190
198
|
params[paramNames[i]] = matches[i + 1];
|
|
191
199
|
}
|
|
192
200
|
if (
|
|
193
201
|
path.includes(":") &&
|
|
194
202
|
window.location.hash.substring(1).split("?")[1]
|
|
195
203
|
) {
|
|
204
|
+
|
|
205
|
+
|
|
196
206
|
return false;
|
|
197
207
|
}
|
|
198
|
-
/**
|
|
199
|
-
* @alias query
|
|
200
|
-
* @type {Object}
|
|
201
|
-
* @property {Object} params - The params object.
|
|
202
|
-
*/
|
|
203
208
|
const query = {};
|
|
204
209
|
|
|
205
210
|
const queryString = window.location.hash.substring(1).split("?")[1];
|
|
@@ -223,11 +228,11 @@ class VaderRouter {
|
|
|
223
228
|
url: window.location.hash.substring(1),
|
|
224
229
|
method: "GET",
|
|
225
230
|
};
|
|
226
|
-
|
|
231
|
+
// @ts-ignore
|
|
227
232
|
window.$URL_PARAMS = params;
|
|
228
|
-
|
|
233
|
+
// @ts-ignore
|
|
229
234
|
window.$URL_QUERY = query;
|
|
230
|
-
|
|
235
|
+
// @ts-ignore
|
|
231
236
|
window.$CURRENT_URL = window.location.hash.substring(1);
|
|
232
237
|
/**
|
|
233
238
|
* @alias render
|
|
@@ -238,26 +243,23 @@ class VaderRouter {
|
|
|
238
243
|
* @description Allows you to perform actions when the currentRoute changes.
|
|
239
244
|
*/
|
|
240
245
|
const res = {
|
|
241
|
-
|
|
246
|
+
return: function (data) {
|
|
247
|
+
this.hooked = false;
|
|
248
|
+
},
|
|
242
249
|
render: function (selector, data) {
|
|
243
250
|
document.querySelector(selector).innerHTML = data;
|
|
244
251
|
},
|
|
245
252
|
};
|
|
246
253
|
|
|
247
254
|
callback(req, res);
|
|
248
|
-
|
|
255
|
+
// @ts-ignore
|
|
249
256
|
return true;
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
this.hooked = false;
|
|
253
260
|
return false;
|
|
254
261
|
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* @alias kill
|
|
258
|
-
* @description Allows you to kill a route.
|
|
259
|
-
* @param {string} path
|
|
260
|
-
*/
|
|
262
|
+
|
|
261
263
|
kill(path) {
|
|
262
264
|
if (this.routes[path]) {
|
|
263
265
|
delete this.routes[path];
|
|
@@ -266,36 +268,36 @@ class VaderRouter {
|
|
|
266
268
|
/**
|
|
267
269
|
* @alias use
|
|
268
270
|
* @param {String} pattern
|
|
269
|
-
* @param {
|
|
271
|
+
* @param { void} callback
|
|
270
272
|
* @returns {void}
|
|
271
273
|
* @memberof VaderRouter
|
|
272
274
|
* @description Allows you to set routes to be used throughout your spa.
|
|
273
275
|
*/
|
|
274
|
-
use(pattern, callback
|
|
276
|
+
use(pattern, callback) {
|
|
275
277
|
const regexPattern = pattern
|
|
276
278
|
.replace(/:[^/]+/g, "([^/]+)") // Replace :param with a capturing group
|
|
277
279
|
.replace(/\//g, "\\/"); // Escape forward slashes
|
|
278
|
-
|
|
280
|
+
|
|
279
281
|
const regex = new RegExp("^" + regexPattern + "(\\?(.*))?$");
|
|
280
282
|
let params = {};
|
|
281
283
|
let query = {};
|
|
282
|
-
|
|
284
|
+
|
|
283
285
|
// Get params
|
|
284
286
|
const match = window.location.hash.substring(1).match(regex);
|
|
285
|
-
|
|
287
|
+
|
|
286
288
|
if (match) {
|
|
287
289
|
this.storedroutes.push(window.location.hash.substring(1));
|
|
288
290
|
const matches = match.slice(1); // Extract matched groups
|
|
289
|
-
|
|
291
|
+
|
|
290
292
|
// Extract named params from the pattern
|
|
291
293
|
const paramNames = pattern.match(/:[^/]+/g) || [];
|
|
292
294
|
for (let i = 0; i < paramNames.length; i++) {
|
|
293
295
|
const paramName = paramNames[i].substring(1); // Remove the leading ":"
|
|
294
296
|
params[paramName] = matches[i];
|
|
295
297
|
}
|
|
296
|
-
|
|
298
|
+
|
|
297
299
|
query = {};
|
|
298
|
-
|
|
300
|
+
|
|
299
301
|
const queryString = matches[paramNames.length]; // The last match is the query string
|
|
300
302
|
if (queryString) {
|
|
301
303
|
const queryParts = queryString.split("&");
|
|
@@ -305,11 +307,11 @@ class VaderRouter {
|
|
|
305
307
|
}
|
|
306
308
|
}
|
|
307
309
|
}
|
|
308
|
-
|
|
310
|
+
// @ts-ignore
|
|
309
311
|
window.$URL_PARAMS = params;
|
|
310
|
-
|
|
312
|
+
// @ts-ignore
|
|
311
313
|
window.$URL_QUERY = query;
|
|
312
|
-
|
|
314
|
+
//@ts-ignore
|
|
313
315
|
if (callback) {
|
|
314
316
|
this.routes[pattern] = callback;
|
|
315
317
|
} else {
|
|
@@ -317,16 +319,14 @@ class VaderRouter {
|
|
|
317
319
|
this.storedroutes.push(window.location.hash.substring(1));
|
|
318
320
|
}
|
|
319
321
|
}
|
|
322
|
+
|
|
323
|
+
|
|
320
324
|
|
|
321
|
-
/**
|
|
322
|
-
* @alias onload
|
|
323
|
-
* @param {Function} callback
|
|
324
|
-
*/
|
|
325
325
|
onload(callback) {
|
|
326
326
|
// await dom to be done make sure no new elements are added
|
|
327
327
|
if (
|
|
328
328
|
document.readyState === "complete" ||
|
|
329
|
-
|
|
329
|
+
// @ts-ignore
|
|
330
330
|
document.readyState === "loaded" ||
|
|
331
331
|
document.readyState === "interactive"
|
|
332
332
|
) {
|
|
@@ -345,16 +345,8 @@ class VaderRouter {
|
|
|
345
345
|
*/
|
|
346
346
|
on(path, callback) {
|
|
347
347
|
window.addEventListener("hashchange", () => {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
* @typedef {Array}
|
|
351
|
-
*/
|
|
352
|
-
const paramNames = new Array();
|
|
353
|
-
/**
|
|
354
|
-
* @alias queryNames
|
|
355
|
-
* @typedef {Array}
|
|
356
|
-
*/
|
|
357
|
-
const queryNames = new Array();
|
|
348
|
+
const paramNames = [];
|
|
349
|
+
const queryNames = [];
|
|
358
350
|
const parsedPath = path
|
|
359
351
|
.split("/")
|
|
360
352
|
.map((part) => {
|
|
@@ -389,11 +381,11 @@ class VaderRouter {
|
|
|
389
381
|
this.currentUrl = route;
|
|
390
382
|
// @ts-ignore
|
|
391
383
|
window.$CURRENT_URL = route;
|
|
392
|
-
|
|
384
|
+
// @ts-ignore
|
|
393
385
|
window.$URL_PARAMS = {};
|
|
394
386
|
if (
|
|
395
387
|
window.location.hash.substring(1).match(regex) &&
|
|
396
|
-
|
|
388
|
+
// @ts-ignore
|
|
397
389
|
this.routes[window.$CURRENT_URL]
|
|
398
390
|
) {
|
|
399
391
|
this.storedroutes.push(window.location.hash.substring(1));
|
|
@@ -401,7 +393,7 @@ class VaderRouter {
|
|
|
401
393
|
const params = {};
|
|
402
394
|
|
|
403
395
|
for (let i = 0; i < paramNames.length; i++) {
|
|
404
|
-
|
|
396
|
+
//@ts-ignore
|
|
405
397
|
params[paramNames[i]] = matches[i + 1];
|
|
406
398
|
}
|
|
407
399
|
if (
|
|
@@ -422,7 +414,6 @@ class VaderRouter {
|
|
|
422
414
|
const queryParts = queryString.split("&");
|
|
423
415
|
for (let i = 0; i < queryParts.length; i++) {
|
|
424
416
|
const queryParam = queryParts[i].split("=");
|
|
425
|
-
// @ts-ignore
|
|
426
417
|
query[queryParam[0]] = queryParam[1];
|
|
427
418
|
}
|
|
428
419
|
}
|
|
@@ -433,7 +424,9 @@ class VaderRouter {
|
|
|
433
424
|
method: "POST",
|
|
434
425
|
};
|
|
435
426
|
const res = {
|
|
436
|
-
|
|
427
|
+
return: function (data) {
|
|
428
|
+
this.hooked = false;
|
|
429
|
+
},
|
|
437
430
|
/**
|
|
438
431
|
* @alias send
|
|
439
432
|
* @param {String} selector
|
|
@@ -445,7 +438,7 @@ class VaderRouter {
|
|
|
445
438
|
* res.send('#root', '<h1>Hello World</h1>');
|
|
446
439
|
* */
|
|
447
440
|
send: function (selector, data) {
|
|
448
|
-
|
|
441
|
+
//@ts-ignore
|
|
449
442
|
document.querySelector(selector).innerHTML = data;
|
|
450
443
|
},
|
|
451
444
|
/**
|
|
@@ -457,13 +450,13 @@ class VaderRouter {
|
|
|
457
450
|
* @description Allows you to perform actions when the currentRoute changes.
|
|
458
451
|
*/
|
|
459
452
|
render: function (selector, data) {
|
|
460
|
-
|
|
453
|
+
//@ts-ignore
|
|
461
454
|
document.querySelector(selector).innerHTML = data;
|
|
462
455
|
},
|
|
463
456
|
};
|
|
464
|
-
|
|
457
|
+
// @ts-ignore
|
|
465
458
|
window.$URL_QUERY = query;
|
|
466
|
-
|
|
459
|
+
// @ts-ignore
|
|
467
460
|
window.$URL_PARAMS = params;
|
|
468
461
|
|
|
469
462
|
/**
|
|
@@ -475,10 +468,10 @@ class VaderRouter {
|
|
|
475
468
|
* @description Allows you to perform actions when the currentRoute changes.
|
|
476
469
|
*/
|
|
477
470
|
callback(req, res);
|
|
478
|
-
}
|
|
479
|
-
console.log(
|
|
471
|
+
}else{
|
|
472
|
+
console.log('no route')
|
|
480
473
|
}
|
|
481
474
|
});
|
|
482
475
|
}
|
|
483
476
|
}
|
|
484
|
-
export default VaderRouter;
|
|
477
|
+
export default VaderRouter;
|