vsn 0.1.50 → 0.1.51
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 +61 -182
- package/demo/markup-default.html +2 -0
- package/demo/vsn.js +1 -1
- package/dist/AST/XHRNode.js +2 -0
- package/dist/AST/XHRNode.js.map +1 -1
- package/dist/AST.js +1 -1
- package/dist/AST.js.map +1 -1
- package/dist/DOM.d.ts +1 -1
- package/dist/DOM.js +1 -1
- package/dist/Scope/QueryReference.js +2 -2
- package/dist/Tag.d.ts +3 -1
- package/dist/Tag.js +25 -19
- package/dist/Tag.js.map +1 -1
- package/dist/attributes/LazyAttribute.d.ts +8 -0
- package/dist/attributes/LazyAttribute.js +120 -0
- package/dist/attributes/LazyAttribute.js.map +1 -0
- package/dist/attributes/List.js +1 -1
- package/dist/attributes/_imports.d.ts +1 -0
- package/dist/attributes/_imports.js +3 -1
- package/dist/attributes/_imports.js.map +1 -1
- package/dist/helpers/VisionHelper.d.ts +1 -0
- package/dist/helpers/VisionHelper.js +15 -0
- package/dist/helpers/VisionHelper.js.map +1 -1
- package/dist/vsn.js +1 -1
- package/package.json +1 -1
- package/src/AST/XHRNode.ts +3 -2
- package/src/AST.ts +1 -2
- package/src/DOM.ts +1 -1
- package/src/Scope/QueryReference.ts +2 -2
- package/src/Tag.ts +23 -15
- package/src/attributes/LazyAttribute.ts +26 -0
- package/src/attributes/List.ts +1 -1
- package/src/attributes/_imports.ts +1 -0
- package/src/helpers/VisionHelper.ts +19 -0
- package/src/vsn.ts +1 -1
- package/test/Controller.spec.ts +4 -4
- package/test/DOM.spec.ts +2 -2
- package/test/attributes/Styles.spec.ts +1 -1
- package/examples/attribute-binding.html +0 -29
package/src/AST/XHRNode.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {Scope} from "../Scope";
|
|
|
4
4
|
import {DOM} from "../DOM";
|
|
5
5
|
import {Tag} from "../Tag";
|
|
6
6
|
import {ScopeDataAbstract} from "../Scope/ScopeDataAbstract";
|
|
7
|
+
import {VisionHelper} from "../helpers/VisionHelper";
|
|
7
8
|
|
|
8
9
|
export class XHRNode extends Node implements TreeNode {
|
|
9
10
|
constructor(
|
|
@@ -22,7 +23,7 @@ export class XHRNode extends Node implements TreeNode {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
async evaluate(scope: Scope, dom: DOM, tag?: Tag) {
|
|
25
|
-
|
|
26
|
+
let url = await this.url.evaluate(scope, dom, tag);
|
|
26
27
|
let method: string;
|
|
27
28
|
let data = this.left ? await this.left.evaluate(scope, dom, tag) : {};
|
|
28
29
|
|
|
@@ -51,7 +52,7 @@ export class XHRNode extends Node implements TreeNode {
|
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
if (request.method === 'GET') {
|
|
54
|
-
|
|
55
|
+
url = VisionHelper.getUriWithParams(url, data);
|
|
55
56
|
} else {
|
|
56
57
|
request['body'] = (typeof data === "string") ? data : JSON.stringify(data);
|
|
57
58
|
}
|
package/src/AST.ts
CHANGED
|
@@ -296,7 +296,7 @@ const TOKEN_PATTERNS: TokenPattern[] = [
|
|
|
296
296
|
},
|
|
297
297
|
{
|
|
298
298
|
type: TokenType.STRING_LITERAL,
|
|
299
|
-
pattern: /^'([^']*)'/
|
|
299
|
+
pattern: /^'([^']*)'/
|
|
300
300
|
},
|
|
301
301
|
{
|
|
302
302
|
type: TokenType.AND,
|
|
@@ -354,7 +354,6 @@ export interface TreeNode<T = any> {
|
|
|
354
354
|
prepare(scope: Scope, dom: DOM, tag?: Tag);
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
|
|
358
357
|
export interface IBlockInfo {
|
|
359
358
|
type: BlockType,
|
|
360
359
|
open: TokenType,
|
package/src/DOM.ts
CHANGED
|
@@ -100,7 +100,7 @@ export class DOM extends EventDispatcher {
|
|
|
100
100
|
return this.rootElement.querySelector(q);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
public async
|
|
103
|
+
public async exec(code: string) {
|
|
104
104
|
const tree = new Tree(code);
|
|
105
105
|
await tree.prepare(this.root.scope, this);
|
|
106
106
|
return await tree.evaluate(this.root.scope, this);
|
|
@@ -14,7 +14,7 @@ export class QueryReference extends ScopeReference {
|
|
|
14
14
|
public async getScope() {
|
|
15
15
|
let parts: string[] = this.path.split('.');
|
|
16
16
|
parts = parts.splice(0, parts.length - 1);
|
|
17
|
-
const qResult = await DOM.instance.
|
|
17
|
+
const qResult = await DOM.instance.exec(parts.join('.'));
|
|
18
18
|
return qResult.length === 1 ? qResult[0].scope : qResult.map((dobj) => dobj.scope);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -24,6 +24,6 @@ export class QueryReference extends ScopeReference {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
public async getValue() {
|
|
27
|
-
return await DOM.instance.
|
|
27
|
+
return await DOM.instance.exec(this.path);
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/Tag.ts
CHANGED
|
@@ -108,7 +108,7 @@ export class Tag extends DOMObject {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
public async
|
|
111
|
+
public async exec(code: string) {
|
|
112
112
|
const tree = new Tree(code);
|
|
113
113
|
await tree.prepare(this.scope, this.dom, this);
|
|
114
114
|
return await tree.evaluate(this.scope, this.dom, this);
|
|
@@ -556,13 +556,20 @@ export class Tag extends DOMObject {
|
|
|
556
556
|
this.onEventHandlers[eventType].push(handler);
|
|
557
557
|
}
|
|
558
558
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
559
|
+
public removeEventHandler(eventType: string, handler) {
|
|
560
|
+
if (!this.onEventHandlers[eventType])
|
|
561
|
+
return;
|
|
562
|
+
|
|
563
|
+
const index = this.onEventHandlers[eventType].indexOf(handler);
|
|
564
|
+
if (index > -1) {
|
|
565
|
+
this.onEventHandlers[eventType].splice(index, 1);
|
|
566
|
+
if (this.onEventHandlers[eventType].length === 0) {
|
|
567
|
+
this.element.removeEventListener(eventType, this.handleEvent.bind(this, eventType));
|
|
563
568
|
}
|
|
564
569
|
}
|
|
570
|
+
}
|
|
565
571
|
|
|
572
|
+
public createScope() {
|
|
566
573
|
// Standard attribute requires a unique scope
|
|
567
574
|
// @todo: Does this cause any issues with attribute bindings on the parent scope prior to having its own scope? hmm...
|
|
568
575
|
if (!this.uniqueScope) {
|
|
@@ -573,6 +580,16 @@ export class Tag extends DOMObject {
|
|
|
573
580
|
this.scope.parentScope = this.parentTag.scope;
|
|
574
581
|
}
|
|
575
582
|
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
async watchAttribute(attributeName: string) {
|
|
586
|
+
for (const attribute of this.attributes) {
|
|
587
|
+
if (attribute instanceof StandardAttribute && attribute.attributeName == attributeName) {
|
|
588
|
+
return attribute;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
this.createScope();
|
|
576
593
|
|
|
577
594
|
const standardAttribute = new StandardAttribute(this, attributeName);
|
|
578
595
|
this.attributes.push(standardAttribute);
|
|
@@ -588,16 +605,7 @@ export class Tag extends DOMObject {
|
|
|
588
605
|
}
|
|
589
606
|
}
|
|
590
607
|
|
|
591
|
-
|
|
592
|
-
// @todo: Does this cause any issues with attribute bindings on the parent scope prior to having its own scope? hmm...
|
|
593
|
-
if (!this.uniqueScope) {
|
|
594
|
-
this._uniqueScope = true;
|
|
595
|
-
this._scope = new Scope();
|
|
596
|
-
|
|
597
|
-
if (this.parentTag) {
|
|
598
|
-
this.scope.parentScope = this.parentTag.scope;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
608
|
+
this.createScope();
|
|
601
609
|
|
|
602
610
|
const styleAttribute = new StyleAttribute(this, 'style');
|
|
603
611
|
this.attributes.push(styleAttribute);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {Registry} from "../Registry";
|
|
2
|
+
import {On} from "./On";
|
|
3
|
+
|
|
4
|
+
@Registry.attribute('vsn-lazy')
|
|
5
|
+
export class LazyAttribute extends On {
|
|
6
|
+
private loaded: boolean = false;
|
|
7
|
+
private eleTop: number;
|
|
8
|
+
|
|
9
|
+
public async setup() {
|
|
10
|
+
await super.setup();
|
|
11
|
+
this.eleTop = this.tag.element.getBoundingClientRect().top;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async connect() {
|
|
15
|
+
this.tag.addEventHandler('scroll', ['passive'], this.handleEvent.bind(this));
|
|
16
|
+
await this.handleEvent();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async handleEvent(e?: Event) {
|
|
20
|
+
if (!this.loaded && window.scrollY + window.outerHeight >= this.eleTop) {
|
|
21
|
+
this.loaded = true;
|
|
22
|
+
await this.handler.evaluate(this.tag.scope, this.tag.dom, this.tag);
|
|
23
|
+
this.tag.removeEventHandler('scroll', this.handleEvent.bind(this));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/attributes/List.ts
CHANGED
|
@@ -37,7 +37,7 @@ export class List extends Attribute {
|
|
|
37
37
|
}
|
|
38
38
|
} else {
|
|
39
39
|
if (this.tag.hasRawAttribute('template')) {
|
|
40
|
-
let templateNode = await DOM.instance.
|
|
40
|
+
let templateNode = await DOM.instance.exec(this.tag.getRawAttributeValue('template'));
|
|
41
41
|
if (templateNode instanceof Array && templateNode.length === 1)
|
|
42
42
|
templateNode = templateNode[0];
|
|
43
43
|
|
|
@@ -8,6 +8,7 @@ export {If} from "./If";
|
|
|
8
8
|
export {JSONAttribute} from "./JSONAttribute";
|
|
9
9
|
export {KeyDown} from "./KeyDown";
|
|
10
10
|
export {KeyUp} from "./KeyUp";
|
|
11
|
+
export {LazyAttribute} from "./LazyAttribute";
|
|
11
12
|
export {List} from "./List";
|
|
12
13
|
export {ListItem} from "./ListItem";
|
|
13
14
|
export {ListItemModel} from "./ListItemModel";
|
|
@@ -40,6 +40,25 @@ export class VisionHelper {
|
|
|
40
40
|
return process.env.BUILD_TARGET === 'es5';
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
public static getUriWithParams(
|
|
44
|
+
url: string,
|
|
45
|
+
params: Record<string, any>
|
|
46
|
+
): string {
|
|
47
|
+
let base = window.location.origin;
|
|
48
|
+
if (url.startsWith('.') || !url.startsWith('/')) {
|
|
49
|
+
base += window.location.pathname;
|
|
50
|
+
}
|
|
51
|
+
const _url = new URL(url, base);
|
|
52
|
+
const urlParams: URLSearchParams = new URLSearchParams(_url.search);
|
|
53
|
+
for (const key in params) {
|
|
54
|
+
if (params[key] !== undefined) {
|
|
55
|
+
urlParams.set(key, params[key]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
_url.search = urlParams.toString();
|
|
59
|
+
return _url.toString();
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
public static nice(callback, timeout: number = 100) {
|
|
44
63
|
if (VisionHelper.window && window['requestIdleCallback']) {
|
|
45
64
|
window['requestIdleCallback'](callback);
|
package/src/vsn.ts
CHANGED
package/test/Controller.spec.ts
CHANGED
|
@@ -33,10 +33,10 @@ describe('Controller', () => {
|
|
|
33
33
|
const dom = new DOM(document);
|
|
34
34
|
const deferred = SimplePromise.defer();
|
|
35
35
|
dom.once('built', async () => {
|
|
36
|
-
expect(await dom.
|
|
37
|
-
expect(await dom.
|
|
38
|
-
await dom.
|
|
39
|
-
expect(await dom.
|
|
36
|
+
expect(await dom.exec('test.test')).toBe('notTest');
|
|
37
|
+
expect(await dom.exec('test.isValid()')).toBe(false);
|
|
38
|
+
await dom.exec('test.test = "test"');
|
|
39
|
+
expect(await dom.exec('test.isValid()')).toBe(true);
|
|
40
40
|
deferred.resolve();
|
|
41
41
|
});
|
|
42
42
|
await deferred.promise;
|
package/test/DOM.spec.ts
CHANGED
|
@@ -28,8 +28,8 @@ describe('DOM', () => {
|
|
|
28
28
|
`;
|
|
29
29
|
const dom = new DOM(document);
|
|
30
30
|
dom.once('built', async () => {
|
|
31
|
-
expect(await dom.
|
|
32
|
-
expect(await dom.
|
|
31
|
+
expect(await dom.exec('?(#parent).asd')).toBe(123);
|
|
32
|
+
expect(await dom.exec('?(#testing).asd')).toBe(345);
|
|
33
33
|
done();
|
|
34
34
|
});
|
|
35
35
|
});
|
|
@@ -35,7 +35,7 @@ describe('Styles', () => {
|
|
|
35
35
|
`;
|
|
36
36
|
const dom = new DOM(document);
|
|
37
37
|
dom.once('built', async () => {
|
|
38
|
-
await dom.
|
|
38
|
+
await dom.exec('?(#styling).$marginTop = "50px"');
|
|
39
39
|
expect((await dom.get('#styling'))[0].element.style.marginTop).toBe('50px');
|
|
40
40
|
done();
|
|
41
41
|
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<h2>The Link</h2>
|
|
2
|
-
<p>v-bind:href binds the scope variable to the element's href attribute. v-name creates a variable scope to hold the url and text variables. Note: You could remove the v-name and the link. from all of the bindings to set the values to the root scope.</p>
|
|
3
|
-
<div>
|
|
4
|
-
<a href="/index.html" v-name="link" v-bind:href="link.url" v-bind="link.text">Home</a>
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
<h2>Text Values</h2>
|
|
8
|
-
<p>Bind an element's innerText with v-bind.</p>
|
|
9
|
-
<div>URL: <span v-bind="link.url"></span>, Text: <span v-bind="link.text"></span></div>
|
|
10
|
-
|
|
11
|
-
<h2>Change Values with Button Click</h2>
|
|
12
|
-
<div>
|
|
13
|
-
<button id="button-help" v-click="link.url='/help.html';link.text='Help';">Change to Help</button>
|
|
14
|
-
<button id="button-info" v-click="link.url='/info.html';link.text='Info';">Change to Info</button>
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<h2>Change Values with Inputs</h2>
|
|
18
|
-
<p>v-bind on inputs binds the inputs values to the scope variable.</p>
|
|
19
|
-
<div>
|
|
20
|
-
<label>
|
|
21
|
-
Link Text:
|
|
22
|
-
<input type="text" v-bind="link.text" />
|
|
23
|
-
</label>
|
|
24
|
-
|
|
25
|
-
<label>
|
|
26
|
-
Link URL:
|
|
27
|
-
<input type="text" v-bind="link.url" />
|
|
28
|
-
</label>
|
|
29
|
-
</div>
|