vsn 0.1.54 → 0.1.57
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/demo/demo.html +184 -62
- package/demo/vsn.js +2 -1
- package/dist/AST/FunctionNode.d.ts +18 -0
- package/dist/AST/FunctionNode.js +87 -0
- package/dist/AST/FunctionNode.js.map +1 -1
- package/dist/DOM/DOMObject.d.ts +6 -1
- package/dist/DOM/DOMObject.js.map +1 -1
- package/dist/DOM.js +46 -76
- package/dist/DOM.js.map +1 -1
- package/dist/Tag.d.ts +4 -3
- package/dist/Tag.js +48 -19
- package/dist/Tag.js.map +1 -1
- package/dist/Types.js +1 -1
- package/dist/Types.js.map +1 -1
- package/dist/attributes/Bind.js.map +1 -1
- package/dist/attributes/KeyAbstract.js +1 -1
- package/dist/attributes/KeyAbstract.js.map +1 -1
- package/dist/attributes/KeyDown.js +1 -1
- package/dist/attributes/KeyDown.js.map +1 -1
- package/dist/attributes/KeyUp.js +1 -1
- package/dist/attributes/KeyUp.js.map +1 -1
- package/dist/attributes/LazyAttribute.js +2 -2
- package/dist/attributes/LazyAttribute.js.map +1 -1
- package/dist/attributes/List.js +13 -9
- package/dist/attributes/List.js.map +1 -1
- package/dist/attributes/On.js +1 -1
- package/dist/attributes/On.js.map +1 -1
- package/dist/attributes/ScopeAttribute.js +15 -5
- package/dist/attributes/ScopeAttribute.js.map +1 -1
- package/dist/vsn.d.ts +1 -1
- package/dist/vsn.js +2 -2
- package/dist/vsn.js.map +1 -1
- package/dist/vsn.min.js +2 -0
- package/package.json +3 -4
- package/src/AST/FunctionNode.ts +31 -0
- package/src/DOM/DOMObject.ts +7 -1
- package/src/DOM.ts +0 -20
- package/src/Tag.ts +41 -14
- package/src/Types.ts +1 -1
- package/src/attributes/Bind.ts +1 -2
- package/src/attributes/KeyAbstract.ts +1 -1
- package/src/attributes/KeyDown.ts +1 -1
- package/src/attributes/KeyUp.ts +1 -1
- package/src/attributes/LazyAttribute.ts +2 -2
- package/src/attributes/List.ts +2 -0
- package/src/attributes/On.ts +1 -1
- package/src/vsn.ts +2 -2
- package/test/attributes/ListItem.spec.ts +1 -0
- package/webpack.config.js +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vsn",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.57",
|
|
4
4
|
"description": "SEO Friendly Javascript/Typescript Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -15,11 +15,10 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "rm -rf ./dist/ && tsc",
|
|
17
17
|
"build_dev": "rm -rf ./dist/ && webpack --env BUILD=development BENCHMARK=1",
|
|
18
|
-
"demo": "
|
|
19
|
-
"clean": "rm -rf ./dist/",
|
|
18
|
+
"demo": "webpack --env BUILD=production BENCHMARK=1 && cp ./dist/vsn.min.js ./demo/vsn.js",
|
|
20
19
|
"test": "karma start --single-run",
|
|
21
20
|
"posttest": "codecov",
|
|
22
|
-
"
|
|
21
|
+
"clean": "rm -rf ./dist/"
|
|
23
22
|
},
|
|
24
23
|
"license": "MIT",
|
|
25
24
|
"dependencies": {},
|
package/src/AST/FunctionNode.ts
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {Scope} from "../Scope";
|
|
2
|
+
import {DOM} from "../DOM";
|
|
3
|
+
import {Tag} from "../Tag";
|
|
4
|
+
import {Token, TreeNode} from "../AST";
|
|
5
|
+
import {Node} from "./Node";
|
|
6
|
+
import {LiteralNode} from "./LiteralNode";
|
|
7
|
+
import {RootScopeMemberNode} from "./RootScopeMemberNode";
|
|
8
|
+
import {ScopeMemberNode} from "./ScopeMemberNode";
|
|
9
|
+
|
|
10
|
+
export class FunctionNode extends Node implements TreeNode {
|
|
11
|
+
constructor(
|
|
12
|
+
public readonly name: LiteralNode<string>,
|
|
13
|
+
public readonly variables: LiteralNode<string>[],
|
|
14
|
+
public readonly block: RootScopeMemberNode | ScopeMemberNode,
|
|
15
|
+
) {
|
|
16
|
+
super();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected _getChildNodes(): Node[] {
|
|
20
|
+
return [
|
|
21
|
+
this.block
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async prepare(scope: Scope, dom: DOM, tag: Tag = null) {}
|
|
26
|
+
public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {}
|
|
27
|
+
|
|
28
|
+
public static parse(lastNode, token, tokens: Token[]): FunctionNode {
|
|
29
|
+
return new FunctionNode(null, null, null);
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/DOM/DOMObject.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import {Scope} from "../Scope";
|
|
2
2
|
import {EventDispatcher} from "../EventDispatcher";
|
|
3
3
|
|
|
4
|
+
export interface IEventHandler {
|
|
5
|
+
event: string;
|
|
6
|
+
handler: (...args: any[]) => any;
|
|
7
|
+
context?: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
export abstract class DOMObject extends EventDispatcher {
|
|
5
11
|
protected _scope: Scope;
|
|
6
|
-
protected onEventHandlers: {[key:string]:
|
|
12
|
+
protected onEventHandlers: {[key:string]: IEventHandler[]};
|
|
7
13
|
protected _uniqueScope: boolean = false;
|
|
8
14
|
|
|
9
15
|
constructor(
|
package/src/DOM.ts
CHANGED
|
@@ -177,26 +177,6 @@ export class DOM extends EventDispatcher {
|
|
|
177
177
|
for (const tag of newTags)
|
|
178
178
|
await tag.compileAttributes();
|
|
179
179
|
|
|
180
|
-
for (const tag of newTags) {
|
|
181
|
-
if (tag === this.root)
|
|
182
|
-
continue;
|
|
183
|
-
|
|
184
|
-
// Find the closest ancestor
|
|
185
|
-
let parentElement: HTMLElement = tag.element.parentElement as HTMLElement;
|
|
186
|
-
let foundParent = false;
|
|
187
|
-
while (parentElement) {
|
|
188
|
-
if (allElements.indexOf(parentElement) > -1) {
|
|
189
|
-
foundParent = true;
|
|
190
|
-
tag.parentTag = await this.getTagForElement(parentElement);
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
parentElement = parentElement.parentElement as HTMLElement;
|
|
195
|
-
}
|
|
196
|
-
if (!foundParent)
|
|
197
|
-
console.error('Could not find parent for ', tag);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
180
|
for (const tag of newTags)
|
|
201
181
|
await tag.setupAttributes();
|
|
202
182
|
|
package/src/Tag.ts
CHANGED
|
@@ -21,6 +21,8 @@ export enum TagState {
|
|
|
21
21
|
Built,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export const TaggedVariable:string = '_vsn_tag';
|
|
25
|
+
|
|
24
26
|
export class Tag extends DOMObject {
|
|
25
27
|
public readonly rawAttributes: { [key: string]: string; };
|
|
26
28
|
public readonly parsedAttributes: { [key: string]: string[]; };
|
|
@@ -55,6 +57,7 @@ export class Tag extends DOMObject {
|
|
|
55
57
|
...props
|
|
56
58
|
) {
|
|
57
59
|
super(element, props);
|
|
60
|
+
element[TaggedVariable] = this;
|
|
58
61
|
this.rawAttributes = {};
|
|
59
62
|
this.parsedAttributes = {};
|
|
60
63
|
this.attributes = [];
|
|
@@ -232,6 +235,23 @@ export class Tag extends DOMObject {
|
|
|
232
235
|
}
|
|
233
236
|
|
|
234
237
|
public get parentTag(): Tag {
|
|
238
|
+
if (!this._parentTag) {
|
|
239
|
+
let parentElement: HTMLElement = this.element.parentElement as HTMLElement;
|
|
240
|
+
let foundParent = false;
|
|
241
|
+
while (parentElement) {
|
|
242
|
+
if (parentElement[TaggedVariable]) {
|
|
243
|
+
foundParent = true;
|
|
244
|
+
this.parentTag = parentElement[TaggedVariable];
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
parentElement = parentElement.parentElement as HTMLElement;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!foundParent && DOM.instance.root !== this)
|
|
252
|
+
return DOM.instance.root;
|
|
253
|
+
}
|
|
254
|
+
|
|
235
255
|
return this._parentTag;
|
|
236
256
|
}
|
|
237
257
|
|
|
@@ -253,8 +273,8 @@ export class Tag extends DOMObject {
|
|
|
253
273
|
if (this.uniqueScope)
|
|
254
274
|
return this.createScope();
|
|
255
275
|
|
|
256
|
-
if (!!this.
|
|
257
|
-
return this.
|
|
276
|
+
if (!!this.parentTag)
|
|
277
|
+
return this.parentTag.scope;
|
|
258
278
|
|
|
259
279
|
return null;
|
|
260
280
|
}
|
|
@@ -293,7 +313,7 @@ export class Tag extends DOMObject {
|
|
|
293
313
|
}
|
|
294
314
|
|
|
295
315
|
public addToParentElement() {
|
|
296
|
-
this.
|
|
316
|
+
this.parentTag.element.appendChild(this.element)
|
|
297
317
|
}
|
|
298
318
|
|
|
299
319
|
public hide() {
|
|
@@ -307,7 +327,6 @@ export class Tag extends DOMObject {
|
|
|
307
327
|
public findAncestorByAttribute(attr: string, includeSelf: boolean = false): Tag {
|
|
308
328
|
if (includeSelf && this.hasAttribute(attr))
|
|
309
329
|
return this;
|
|
310
|
-
|
|
311
330
|
return this.parentTag ? this.parentTag.findAncestorByAttribute(attr, true) : null;
|
|
312
331
|
}
|
|
313
332
|
|
|
@@ -472,7 +491,7 @@ export class Tag extends DOMObject {
|
|
|
472
491
|
|
|
473
492
|
public async connectAttributes() {
|
|
474
493
|
if (this.isInput) {
|
|
475
|
-
this.addEventHandler('input', [], this.inputMutation
|
|
494
|
+
this.addEventHandler('input', [], this.inputMutation, this);
|
|
476
495
|
}
|
|
477
496
|
|
|
478
497
|
for (const attr of this.nonDeferredAttributes) {
|
|
@@ -496,9 +515,12 @@ export class Tag extends DOMObject {
|
|
|
496
515
|
option.removeAttribute('selected');
|
|
497
516
|
}
|
|
498
517
|
}
|
|
499
|
-
this.element.setAttribute('value',
|
|
518
|
+
//this.element.setAttribute('value', );
|
|
519
|
+
this.value = values.join(',');
|
|
500
520
|
} else {
|
|
501
|
-
this.element.setAttribute('value', e.target.value);
|
|
521
|
+
//this.element.setAttribute('value', e.target.value);
|
|
522
|
+
//(this.element as any).value = e.target.value;
|
|
523
|
+
this.value = e.target.value;
|
|
502
524
|
}
|
|
503
525
|
}
|
|
504
526
|
|
|
@@ -519,13 +541,14 @@ export class Tag extends DOMObject {
|
|
|
519
541
|
protected handleEvent(eventType: string, e) {
|
|
520
542
|
if (e)
|
|
521
543
|
e.stopPropagation();
|
|
544
|
+
|
|
522
545
|
if (!this.onEventHandlers[eventType])
|
|
523
546
|
return;
|
|
524
547
|
|
|
525
548
|
this.scope.set('$event', e);
|
|
526
549
|
this.scope.set('$value', this.value);
|
|
527
550
|
for (const handler of this.onEventHandlers[eventType]) {
|
|
528
|
-
handler(e);
|
|
551
|
+
handler.handler.call(handler.context, e);
|
|
529
552
|
}
|
|
530
553
|
}
|
|
531
554
|
|
|
@@ -537,7 +560,7 @@ export class Tag extends DOMObject {
|
|
|
537
560
|
return attribute.replace(`|${modifier}`, '');
|
|
538
561
|
}
|
|
539
562
|
|
|
540
|
-
public addEventHandler(eventType: string, modifiers: string[], handler) {
|
|
563
|
+
public addEventHandler(eventType: string, modifiers: string[], handler, context: any = null) {
|
|
541
564
|
let passiveValue: boolean = null;
|
|
542
565
|
if (modifiers.indexOf('active') > -1) {
|
|
543
566
|
passiveValue = false;
|
|
@@ -555,16 +578,20 @@ export class Tag extends DOMObject {
|
|
|
555
578
|
element.addEventListener(eventType, this.handleEvent.bind(this, eventType), opts);
|
|
556
579
|
}
|
|
557
580
|
|
|
558
|
-
this.onEventHandlers[eventType].push(
|
|
581
|
+
this.onEventHandlers[eventType].push({
|
|
582
|
+
handler: handler,
|
|
583
|
+
event: eventType,
|
|
584
|
+
context: context,
|
|
585
|
+
});
|
|
559
586
|
}
|
|
560
587
|
|
|
561
|
-
public removeEventHandler(eventType: string, handler) {
|
|
588
|
+
public removeEventHandler(eventType: string, handler, context: any = null) {
|
|
562
589
|
if (!this.onEventHandlers[eventType])
|
|
563
590
|
return;
|
|
564
591
|
|
|
565
|
-
const
|
|
566
|
-
if (
|
|
567
|
-
this.onEventHandlers[eventType].splice(
|
|
592
|
+
const _handler = this.onEventHandlers[eventType].find(h => h.handler === handler && h.context === context);
|
|
593
|
+
if (_handler) {
|
|
594
|
+
this.onEventHandlers[eventType].splice(this.onEventHandlers[eventType].indexOf(_handler), 1);
|
|
568
595
|
if (this.onEventHandlers[eventType].length === 0) {
|
|
569
596
|
this.element.removeEventListener(eventType, this.handleEvent.bind(this, eventType));
|
|
570
597
|
}
|
package/src/Types.ts
CHANGED
package/src/attributes/Bind.ts
CHANGED
|
@@ -44,7 +44,6 @@ export class Bind extends Attribute {
|
|
|
44
44
|
|
|
45
45
|
this.key = await ref.getKey();
|
|
46
46
|
this.boundScope = await ref.getScope();
|
|
47
|
-
|
|
48
47
|
if (!!this.valueFromElement)
|
|
49
48
|
this.updateFrom();
|
|
50
49
|
|
|
@@ -80,12 +79,12 @@ export class Bind extends Attribute {
|
|
|
80
79
|
|
|
81
80
|
get valueFromElement(): string {
|
|
82
81
|
let value;
|
|
82
|
+
|
|
83
83
|
if (this.property) {
|
|
84
84
|
value = this.tag.getElementAttribute(this.property);
|
|
85
85
|
} else {
|
|
86
86
|
value = this.tag.value;
|
|
87
87
|
}
|
|
88
|
-
|
|
89
88
|
return value;
|
|
90
89
|
}
|
|
91
90
|
|
|
@@ -9,7 +9,7 @@ export abstract class KeyAbstract extends On {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
public async connect() {
|
|
12
|
-
this.tag.addEventHandler('keydown', this.getAttributeModifiers(), this.handleEvent
|
|
12
|
+
this.tag.addEventHandler('keydown', this.getAttributeModifiers(), this.handleEvent, this);
|
|
13
13
|
await super.connect();
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ import {Registry} from "../Registry";
|
|
|
4
4
|
@Registry.attribute('vsn-key-down')
|
|
5
5
|
export class KeyDown extends KeyAbstract {
|
|
6
6
|
public async connect() {
|
|
7
|
-
this.tag.addEventHandler('keydown', this.getAttributeModifiers(), this.handleEvent
|
|
7
|
+
this.tag.addEventHandler('keydown', this.getAttributeModifiers(), this.handleEvent, this);
|
|
8
8
|
await super.connect();
|
|
9
9
|
}
|
|
10
10
|
}
|
package/src/attributes/KeyUp.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {Registry} from "../Registry";
|
|
|
4
4
|
@Registry.attribute('vsn-key-up')
|
|
5
5
|
export class KeyUp extends KeyAbstract {
|
|
6
6
|
public async connect() {
|
|
7
|
-
this.tag.addEventHandler('keyup', this.getAttributeModifiers(), this.handleEvent
|
|
7
|
+
this.tag.addEventHandler('keyup', this.getAttributeModifiers(), this.handleEvent, this);
|
|
8
8
|
await super.connect();
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -12,7 +12,7 @@ export class LazyAttribute extends On {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
public async connect() {
|
|
15
|
-
this.tag.addEventHandler('scroll', ['passive'], this.handleEvent
|
|
15
|
+
this.tag.addEventHandler('scroll', ['passive'], this.handleEvent, this);
|
|
16
16
|
await this.handleEvent();
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ export class LazyAttribute extends On {
|
|
|
20
20
|
if (!this.loaded && window.scrollY + window.outerHeight >= this.eleTop) {
|
|
21
21
|
this.loaded = true;
|
|
22
22
|
await this.handler.evaluate(this.tag.scope, this.tag.dom, this.tag);
|
|
23
|
-
this.tag.removeEventHandler('scroll', this.handleEvent
|
|
23
|
+
this.tag.removeEventHandler('scroll', this.handleEvent, this);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/attributes/List.ts
CHANGED
|
@@ -25,9 +25,11 @@ export class List extends Attribute {
|
|
|
25
25
|
public async setup() {
|
|
26
26
|
if (this.tag.element.children.length > 0) {
|
|
27
27
|
const template = this.tag.element.children[0];
|
|
28
|
+
const templateTag: Tag = await this.tag.dom.getTagForElement(template);
|
|
28
29
|
|
|
29
30
|
if (template) {
|
|
30
31
|
if (template.hasAttribute('vsn-template')) {
|
|
32
|
+
templateTag.parentTag = this.tag; // Set parentTag before removing from DOM
|
|
31
33
|
template.removeAttribute('vsn-template');
|
|
32
34
|
this.tag.element.removeChild(template);
|
|
33
35
|
this.template = template;
|
package/src/attributes/On.ts
CHANGED
|
@@ -32,7 +32,7 @@ export abstract class On extends Attribute {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
public async connect() {
|
|
35
|
-
this.tag.addEventHandler(this.getAttributeBinding(), this.getAttributeModifiers(), this.handleEvent
|
|
35
|
+
this.tag.addEventHandler(this.getAttributeBinding(), this.getAttributeModifiers(), this.handleEvent, this);
|
|
36
36
|
await super.connect();
|
|
37
37
|
}
|
|
38
38
|
}
|
package/src/vsn.ts
CHANGED
|
@@ -43,7 +43,7 @@ export class Vision extends EventDispatcher {
|
|
|
43
43
|
return this._dom;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
public async
|
|
46
|
+
public async exec(code: string) {
|
|
47
47
|
return await this._dom.exec(code);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -55,7 +55,7 @@ export class Vision extends EventDispatcher {
|
|
|
55
55
|
await this._dom.buildFrom(document, true);
|
|
56
56
|
const now = (new Date()).getTime();
|
|
57
57
|
const setupTime = now - startTime;
|
|
58
|
-
console.warn(`Took ${setupTime}ms to start up VisionJS. https://www.vsnjs.com
|
|
58
|
+
console.warn(`Took ${setupTime}ms to start up VisionJS. https://www.vsnjs.com/`, window ? `v${window['VSN_VERSION']}` : null);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public static get instance() {
|
package/webpack.config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const webpack = require("webpack");
|
|
3
|
+
const TerserPlugin = require("terser-webpack-plugin");
|
|
3
4
|
|
|
4
5
|
const defaultConfiguration = {
|
|
5
6
|
entry: './src/vsn.ts',
|
|
@@ -20,6 +21,15 @@ const defaultConfiguration = {
|
|
|
20
21
|
filename: 'vsn.min.js',
|
|
21
22
|
path: path.resolve(__dirname, 'dist'),
|
|
22
23
|
},
|
|
24
|
+
optimization: {
|
|
25
|
+
minimizer: [new TerserPlugin({
|
|
26
|
+
terserOptions: {
|
|
27
|
+
format: {
|
|
28
|
+
preamble: `/* Copyright ${new Date().getUTCFullYear()}, VSNjs. ${require('./package.json').name} ${require('./package.json').version} (${new Date().toUTCString()}) */if (window) window['VSN_VERSION']='${require('./package.json').version}';`
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})],
|
|
32
|
+
}
|
|
23
33
|
};
|
|
24
34
|
|
|
25
35
|
function buildConfig(env) {
|