vaderjs 1.3.3-alpha-19 → 1.3.3-alpha-21
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/README.md +176 -158
- package/client/index.js +243 -62
- package/logo.png +0 -0
- package/package.json +1 -1
- package/runtime/index.html +0 -0
- package/runtime/router.js +3 -2
- package/runtime/vader.js +297 -72
- package/vader.js +45 -33
package/client/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
window.params = {};
|
|
3
3
|
window.Vader = {
|
|
4
|
-
version: "1.3.
|
|
4
|
+
version: "1.3.3",
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
let errors = {
|
|
@@ -43,16 +43,13 @@ let hasran = [];
|
|
|
43
43
|
let states = {};
|
|
44
44
|
let mounts = [];
|
|
45
45
|
export const strictMount = (key, callback) => {
|
|
46
|
-
|
|
47
|
-
if(
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
let timer = setInterval(() => {
|
|
47
|
+
if (document.querySelector('[key="' + key + '"]')) {
|
|
48
|
+
console.log('mounted')
|
|
49
|
+
clearInterval(timer);
|
|
50
50
|
callback();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
hasran.push(callback.toString());
|
|
54
|
-
}
|
|
55
|
-
},0);
|
|
51
|
+
}
|
|
52
|
+
}, 120);
|
|
56
53
|
};
|
|
57
54
|
|
|
58
55
|
window.delegate = (event) => {
|
|
@@ -167,9 +164,93 @@ export class Component {
|
|
|
167
164
|
window.listeners = [];
|
|
168
165
|
this.functionMap = new Map();
|
|
169
166
|
this.freeMemoryFromFunctions();
|
|
167
|
+
this.checkIFMounted();
|
|
170
168
|
this.memoizes = []
|
|
169
|
+
|
|
170
|
+
this.vdom = []
|
|
171
|
+
|
|
171
172
|
this.children = []
|
|
173
|
+
let dom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
|
|
174
|
+
dom.querySelectorAll('*').forEach((el) => {
|
|
175
|
+
let obj = {
|
|
176
|
+
el: el,
|
|
177
|
+
tag: el.tagName,
|
|
178
|
+
html: el.innerHTML,
|
|
179
|
+
content: el.textContent,
|
|
180
|
+
value: el.value,
|
|
181
|
+
attributes: el.attributes,
|
|
182
|
+
children: el.childNodes,
|
|
183
|
+
}
|
|
184
|
+
this.vdom.push(obj)
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Parent of the current component.
|
|
189
|
+
* @type {Component}
|
|
190
|
+
*/
|
|
191
|
+
this.parentNode = {}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Request object.
|
|
195
|
+
*/
|
|
196
|
+
this.request = {
|
|
197
|
+
/**
|
|
198
|
+
* @type {string}
|
|
199
|
+
* @description The headers for the current route
|
|
200
|
+
*/
|
|
201
|
+
headers:{},
|
|
202
|
+
/**
|
|
203
|
+
* @type {string}
|
|
204
|
+
* @description The method for the current route
|
|
205
|
+
*/
|
|
206
|
+
method: "GET",
|
|
207
|
+
/**
|
|
208
|
+
* @type {string}
|
|
209
|
+
* @description params for the given route /:id/:name etc
|
|
210
|
+
*/
|
|
211
|
+
params: {},
|
|
212
|
+
/**
|
|
213
|
+
* @type {string}
|
|
214
|
+
* @description path: current route path
|
|
215
|
+
*/
|
|
216
|
+
path: "",
|
|
217
|
+
/**
|
|
218
|
+
* @type {string}
|
|
219
|
+
* @description query: query object for the current route ?name=hello -> {name: 'hello'}
|
|
220
|
+
*/
|
|
221
|
+
query: {},
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* @type {string}
|
|
225
|
+
* @description The response object for the current route
|
|
226
|
+
*/
|
|
227
|
+
this.response = {
|
|
228
|
+
/**
|
|
229
|
+
* @method json
|
|
230
|
+
* @description This method allows you to send json data to the client
|
|
231
|
+
* @param {*} data
|
|
232
|
+
*/
|
|
233
|
+
json: (data) => {},
|
|
234
|
+
/**
|
|
235
|
+
* @method send
|
|
236
|
+
* @description This method allows you to send text data to the client
|
|
237
|
+
* @param {*} data
|
|
238
|
+
*/
|
|
239
|
+
send: (data) => {},
|
|
240
|
+
/**
|
|
241
|
+
* @method redirect
|
|
242
|
+
* @description This method allows you to redirect the client to a new route
|
|
243
|
+
* @param {*} path
|
|
244
|
+
*/
|
|
245
|
+
redirect: (path) => {},
|
|
246
|
+
/**
|
|
247
|
+
* @method render
|
|
248
|
+
* @description render a new component to the client
|
|
249
|
+
* @param {*} Component
|
|
250
|
+
*/
|
|
251
|
+
render: async (Component) => {},
|
|
172
252
|
}
|
|
253
|
+
}
|
|
173
254
|
|
|
174
255
|
createComponent(/**@type {Component}**/component, props, children) {
|
|
175
256
|
|
|
@@ -179,26 +260,16 @@ export class Component {
|
|
|
179
260
|
if(!props.key){
|
|
180
261
|
throw new Error('new components must have a key')
|
|
181
262
|
}
|
|
182
|
-
let comp = new component();
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (newFunc) {
|
|
187
|
-
newFunc = newFunc[0].replace(/this.bind\((.*)\)/gs, "$1");
|
|
188
|
-
newFunc = newFunc.split('`')[1]
|
|
189
|
-
props[key] = this.bind(newFunc, { jsx: true, params: props[key], ref: props.ref });
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
props[key] = props[key].toString().replace('"', '').replace("'", '').replace('${', '').replace('}', '')
|
|
196
|
-
});
|
|
263
|
+
let comp = new component(props);
|
|
264
|
+
if(this.components[props.key]){
|
|
265
|
+
return this.components[props.key]
|
|
266
|
+
}
|
|
197
267
|
comp['props'] = props;
|
|
198
268
|
comp.children = children;
|
|
199
269
|
comp.props.children = children.join('')
|
|
200
270
|
comp.parentNode = this;
|
|
201
271
|
comp.key = props.key || null;
|
|
272
|
+
|
|
202
273
|
this.components[props.key] = comp
|
|
203
274
|
this.children.push(comp)
|
|
204
275
|
return this.components[props.key]
|
|
@@ -215,6 +286,7 @@ export class Component {
|
|
|
215
286
|
}
|
|
216
287
|
|
|
217
288
|
let comp = this.components[component.key];
|
|
289
|
+
|
|
218
290
|
let h = comp.render()
|
|
219
291
|
|
|
220
292
|
if(h && h.split('>,').length > 1){
|
|
@@ -240,28 +312,75 @@ export class Component {
|
|
|
240
312
|
* Hydrates the component by updating the HTML content if it has changed.
|
|
241
313
|
* @private
|
|
242
314
|
*/
|
|
243
|
-
hydrate() {
|
|
244
|
-
if (this.key) {
|
|
245
|
-
|
|
246
|
-
const el = document.querySelector(`[key="${this.key}"]`);
|
|
247
315
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
316
|
+
domDifference(oldDom, newDom) {
|
|
317
|
+
let diff = [];
|
|
318
|
+
|
|
319
|
+
for (let i = 0; i < oldDom.length; i++) {
|
|
320
|
+
let oldEl = oldDom[i];
|
|
321
|
+
let newEl = newDom[i];
|
|
322
|
+
|
|
323
|
+
if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
|
|
324
|
+
diff.push({
|
|
325
|
+
type: 'replace',
|
|
326
|
+
old: oldEl,
|
|
327
|
+
new: newEl.cloneNode(true),
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return diff;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
updateChangedElements(diff) {
|
|
336
|
+
diff.forEach((change) => {
|
|
337
|
+
switch (change.type) {
|
|
338
|
+
case 'replace':
|
|
339
|
+
change.old.parentNode.replaceChild(change.new, change.old);
|
|
340
|
+
break;
|
|
341
|
+
case 'remove':
|
|
342
|
+
change.old.remove();
|
|
343
|
+
break;
|
|
344
|
+
case 'add':
|
|
345
|
+
change.old.appendChild(change.new.cloneNode(true));
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
hydrate(hook) {
|
|
354
|
+
if (this.key) {
|
|
355
|
+
if (hook) {
|
|
356
|
+
let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
|
|
357
|
+
|
|
358
|
+
let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
|
|
359
|
+
let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
|
|
360
|
+
let diff = this.domDifference(oldElements, newElements);
|
|
361
|
+
this.updateChangedElements(diff);
|
|
362
|
+
} else {
|
|
363
|
+
const targetElement = document.querySelector(`[key="${this.key}"]`);
|
|
364
|
+
if (targetElement) {
|
|
365
|
+
targetElement.innerHTML = this.render();
|
|
366
|
+
} else {
|
|
367
|
+
console.error('Target element not found.');
|
|
261
368
|
}
|
|
262
369
|
}
|
|
263
370
|
}
|
|
264
371
|
}
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
patch(oldElements, newElements) {
|
|
376
|
+
const diff = this.domDifference(oldElements, newElements);
|
|
377
|
+
|
|
378
|
+
this.updateChangedElements(diff);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
265
384
|
|
|
266
385
|
/**
|
|
267
386
|
* Handles an object by parsing it as JSON and evaluating it.
|
|
@@ -279,7 +398,7 @@ export class Component {
|
|
|
279
398
|
}
|
|
280
399
|
|
|
281
400
|
/**
|
|
282
|
-
* Frees memory from functions that have not been used for a certain period of time.
|
|
401
|
+
* Frees memory from functions that have not been used for a certain period of time.c
|
|
283
402
|
* @private
|
|
284
403
|
*/
|
|
285
404
|
freeMemoryFromFunctions() {
|
|
@@ -299,23 +418,53 @@ export class Component {
|
|
|
299
418
|
* @param {string} ref - The reference.
|
|
300
419
|
* @returns {string} - A valid inline JS function call.
|
|
301
420
|
*/
|
|
302
|
-
bind(funcData,
|
|
421
|
+
bind(funcData,jsx,ref, paramNames, ...params) {
|
|
422
|
+
|
|
303
423
|
|
|
304
424
|
const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
|
|
305
425
|
|
|
306
|
-
var dynamicFunction = (params) => {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
426
|
+
var dynamicFunction = async (...params) => {
|
|
427
|
+
|
|
428
|
+
// Replace double commas with a single comma
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
// Turn params into a destructured object
|
|
432
|
+
let paramObject = {};
|
|
433
|
+
params = params[0]
|
|
434
|
+
|
|
435
|
+
paramNames = paramNames.replace(/,,/g, ',');
|
|
436
|
+
let newparamnames = paramNames.replaceAll(',,', ',')
|
|
437
|
+
params.forEach((param, index) => {
|
|
438
|
+
if(param && Object.keys(param).includes('detail')){
|
|
439
|
+
param = param['detail']['target']['event']
|
|
440
|
+
params[index] = param
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
// Remove trailing commas
|
|
444
|
+
paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
|
|
445
|
+
console.log(paramNames)
|
|
446
|
+
|
|
447
|
+
params.forEach((param, index) => {
|
|
448
|
+
paramObject[newparamnames.split(',')[index]] = param;
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
paramNames = paramNames.replace(',,', ',');
|
|
452
|
+
let func = new Function(`${paramNames}`, `
|
|
453
|
+
return (async (${paramNames}) => {
|
|
454
|
+
${funcData}
|
|
455
|
+
})(${Object.keys(paramObject).join(',')})
|
|
456
|
+
`);
|
|
457
|
+
|
|
458
|
+
// Bind and execute the function with the provided parameters
|
|
459
|
+
await func.bind(this)(...Object.values(paramObject));
|
|
312
460
|
};
|
|
461
|
+
|
|
313
462
|
|
|
314
463
|
dynamicFunction = dynamicFunction.bind(this);
|
|
315
464
|
if (!this.functionMap.has(name)) {
|
|
316
465
|
document.addEventListener(`call_${name}`, (e) => {
|
|
317
466
|
|
|
318
|
-
dynamicFunction();
|
|
467
|
+
dynamicFunction(params);
|
|
319
468
|
this.functionMap.set(e.detail.name, {
|
|
320
469
|
lastUsed: Date.now(),
|
|
321
470
|
});
|
|
@@ -335,15 +484,17 @@ export class Component {
|
|
|
335
484
|
};
|
|
336
485
|
|
|
337
486
|
// Return a valid inline js function call
|
|
338
|
-
return
|
|
487
|
+
return jsx ? dynamicFunction : `
|
|
339
488
|
((event) => {
|
|
340
|
-
event.target.setAttribute('data-ref', '${
|
|
489
|
+
event.target.setAttribute('data-ref', '${ref}');
|
|
341
490
|
let reference = event.target.getAttribute('data-ref');
|
|
342
491
|
event.target.eventData = event;
|
|
492
|
+
|
|
343
493
|
let domquery = queryRef(reference);
|
|
344
|
-
|
|
345
|
-
domquery.eventData
|
|
346
|
-
|
|
494
|
+
|
|
495
|
+
domquery.eventData = event;
|
|
496
|
+
domquery.eventData.target = domquery;
|
|
497
|
+
call('${name}', {event:domquery.eventData}, '${paramNames}')
|
|
347
498
|
})(event)
|
|
348
499
|
`;
|
|
349
500
|
}
|
|
@@ -412,11 +563,14 @@ export class Component {
|
|
|
412
563
|
if (!this.state[key]) {
|
|
413
564
|
this.state[key] = initialState;
|
|
414
565
|
}
|
|
415
|
-
|
|
416
|
-
const
|
|
566
|
+
let updatedValue = () => this.state[key];
|
|
567
|
+
const getValue = updatedValue()
|
|
568
|
+
const set = (newValue, hook) => {
|
|
417
569
|
this.state[key] = newValue;
|
|
418
|
-
this.hydrate();
|
|
570
|
+
this.hydrate(hook);
|
|
419
571
|
};
|
|
572
|
+
this[`set${key}`] = set;
|
|
573
|
+
this[`get${key}`] = getValue;
|
|
420
574
|
return [getValue, set];
|
|
421
575
|
}
|
|
422
576
|
|
|
@@ -429,9 +583,11 @@ export class Component {
|
|
|
429
583
|
this.state[key] = newValue;
|
|
430
584
|
this.hydrate();
|
|
431
585
|
};
|
|
586
|
+
|
|
587
|
+
|
|
432
588
|
return {
|
|
433
|
-
bind: key,
|
|
434
|
-
current:
|
|
589
|
+
bind: key + this.key,
|
|
590
|
+
current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
|
|
435
591
|
}
|
|
436
592
|
}
|
|
437
593
|
|
|
@@ -455,7 +611,7 @@ export class Component {
|
|
|
455
611
|
* @private
|
|
456
612
|
*/
|
|
457
613
|
checkIFMounted() {
|
|
458
|
-
if (this.mounted) return;
|
|
614
|
+
if (this.mounted || !this.key) return;
|
|
459
615
|
let timer = setInterval(() => {
|
|
460
616
|
if (document.querySelector('[key="' + this.key + '"]')) {
|
|
461
617
|
clearInterval(timer);
|
|
@@ -533,6 +689,7 @@ window.require = require;
|
|
|
533
689
|
* @description Allows you to use state to dynamically update your component
|
|
534
690
|
*/
|
|
535
691
|
export const useState = (initialState) => {
|
|
692
|
+
let key = ''
|
|
536
693
|
let value = initialState;
|
|
537
694
|
if (key && !states[key]) {
|
|
538
695
|
this.states[key] = initialState;
|
|
@@ -540,6 +697,16 @@ export const useState = (initialState) => {
|
|
|
540
697
|
return [value, (newValue) => {}];
|
|
541
698
|
};
|
|
542
699
|
|
|
700
|
+
/**
|
|
701
|
+
* @method useReducer
|
|
702
|
+
* @param {*} initialState
|
|
703
|
+
* @param {*} reducer
|
|
704
|
+
* @returns {Array} [value, set]
|
|
705
|
+
*/
|
|
706
|
+
export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
|
|
707
|
+
return [initialState, (newValue) => {}];
|
|
708
|
+
};
|
|
709
|
+
|
|
543
710
|
const constants = {};
|
|
544
711
|
let constantCounter = 0;
|
|
545
712
|
|
|
@@ -550,13 +717,27 @@ export const constant = (value) => {
|
|
|
550
717
|
}
|
|
551
718
|
return constants[key];
|
|
552
719
|
};
|
|
720
|
+
/**
|
|
721
|
+
* @method useRef
|
|
722
|
+
* @description Allows you to use a reference to a DOM element
|
|
723
|
+
* @param {*} initialState
|
|
724
|
+
* @returns
|
|
725
|
+
*/
|
|
553
726
|
|
|
727
|
+
export const useRef = (initialState) => {
|
|
728
|
+
return {
|
|
729
|
+
current: initialState,
|
|
730
|
+
bind: '',
|
|
731
|
+
};
|
|
732
|
+
};
|
|
554
733
|
export default {
|
|
555
734
|
Component,
|
|
556
735
|
require,
|
|
557
736
|
invoke,
|
|
558
737
|
mem,
|
|
559
738
|
constant,
|
|
739
|
+
useRef,
|
|
740
|
+
useReducer,
|
|
560
741
|
useState,
|
|
561
742
|
strictMount,
|
|
562
743
|
stylis,
|
package/logo.png
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/runtime/index.html
CHANGED
|
File without changes
|
package/runtime/router.js
CHANGED
|
@@ -198,8 +198,9 @@ class VaderRouter{
|
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
200
|
},
|
|
201
|
-
redirect: (path) => {
|
|
202
|
-
|
|
201
|
+
redirect: (path) => {
|
|
202
|
+
!path.startsWith('/') ? path = `/${path}` : null;
|
|
203
|
+
window.location.hash = `#${path}`;
|
|
203
204
|
},
|
|
204
205
|
render: async (/**@type {Component} */ Component, req, res) => {
|
|
205
206
|
|