vsn 0.1.19 → 0.1.22
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 +9 -2
- package/demo/vision.js +1 -1
- package/dist/AST.d.ts +2 -1
- package/dist/AST.js +117 -8
- package/dist/AST.js.map +1 -1
- package/dist/DOM/DOMObject.d.ts +1 -0
- package/dist/DOM/DOMObject.js +2 -0
- package/dist/DOM/DOMObject.js.map +1 -1
- package/dist/Scope.d.ts +2 -1
- package/dist/Scope.js +13 -6
- package/dist/Scope.js.map +1 -1
- package/dist/Tag.d.ts +3 -0
- package/dist/Tag.js +49 -0
- package/dist/Tag.js.map +1 -1
- package/dist/Vision.d.ts +1 -1
- package/dist/Vision.js +2 -1
- package/dist/Vision.js.map +1 -1
- package/dist/attributes/StyleAttribute.d.ts +12 -0
- package/dist/attributes/StyleAttribute.js +182 -0
- package/dist/attributes/StyleAttribute.js.map +1 -0
- package/dist/attributes/_imports.d.ts +1 -0
- package/dist/attributes/_imports.js +3 -1
- package/dist/attributes/_imports.js.map +1 -1
- package/package.json +1 -1
- package/src/AST.ts +70 -7
- package/src/DOM/DOMObject.ts +4 -0
- package/src/Scope.ts +11 -8
- package/src/Tag.ts +33 -0
- package/src/Vision.ts +1 -1
- package/src/attributes/StyleAttribute.ts +83 -0
- package/src/attributes/_imports.ts +1 -0
- package/test/attributes/Styles.spec.ts +43 -0
package/src/Tag.ts
CHANGED
|
@@ -8,6 +8,8 @@ import {On} from "./attributes/On";
|
|
|
8
8
|
import {Registry} from "./Registry";
|
|
9
9
|
import {benchmarkEnd, benchmarkStart} from "./Bencmark";
|
|
10
10
|
import {DOMObject} from "./DOM/DOMObject";
|
|
11
|
+
import { Tree } from "./AST";
|
|
12
|
+
import {StyleAttribute} from "./attributes/StyleAttribute";
|
|
11
13
|
|
|
12
14
|
export enum TagState {
|
|
13
15
|
Instantiated,
|
|
@@ -104,6 +106,12 @@ export class Tag extends DOMObject {
|
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
public async eval(code: string) {
|
|
110
|
+
const tree = new Tree(code);
|
|
111
|
+
await tree.prepare(this.scope, this.dom, this);
|
|
112
|
+
return await tree.evaluate(this.scope, this.dom, this);
|
|
113
|
+
}
|
|
114
|
+
|
|
107
115
|
public async evaluate() {
|
|
108
116
|
for (const attr of this.nonDeferredAttributes) {
|
|
109
117
|
await attr.evaluate();
|
|
@@ -480,6 +488,31 @@ export class Tag extends DOMObject {
|
|
|
480
488
|
return standardAttribute;
|
|
481
489
|
}
|
|
482
490
|
|
|
491
|
+
async watchStyle(styleName: string) {
|
|
492
|
+
for (const attribute of this.attributes) {
|
|
493
|
+
if (attribute instanceof StyleAttribute) {
|
|
494
|
+
return attribute;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Standard attribute requires a unique scope
|
|
499
|
+
// @todo: Does this cause any issues with attribute bindings on the parent scope prior to having its own scope? hmm...
|
|
500
|
+
if (!this.uniqueScope) {
|
|
501
|
+
this._uniqueScope = true;
|
|
502
|
+
this._scope = new Scope();
|
|
503
|
+
|
|
504
|
+
if (this.parentTag) {
|
|
505
|
+
this.scope.parentScope = this.parentTag.scope;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const styleAttribute = new StyleAttribute(this, 'style');
|
|
510
|
+
this.attributes.push(styleAttribute);
|
|
511
|
+
await this.setupAttribute(styleAttribute);
|
|
512
|
+
|
|
513
|
+
return styleAttribute;
|
|
514
|
+
}
|
|
515
|
+
|
|
483
516
|
private async setupAttribute(attribute: Attribute) {
|
|
484
517
|
await attribute.compile();
|
|
485
518
|
await attribute.setup();
|
package/src/Vision.ts
CHANGED
|
@@ -72,5 +72,5 @@ export * from './Registry';
|
|
|
72
72
|
export * from './Attribute';
|
|
73
73
|
export * from './AST';
|
|
74
74
|
export {DOM} from './DOM';
|
|
75
|
-
export {WrappedArray, Scope} from './Scope';
|
|
75
|
+
export {WrappedArray, Scope, ScopeReference} from './Scope';
|
|
76
76
|
export const vision: Vision = Vision.instance;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {Registry} from "../Registry";
|
|
2
|
+
import {Attribute} from "../Attribute";
|
|
3
|
+
import {Scope, ScopeReference} from "../Scope";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@Registry.attribute('vsn-styles')
|
|
7
|
+
export class StyleAttribute extends Attribute {
|
|
8
|
+
private scopeRef: ScopeReference;
|
|
9
|
+
private styleScope: Scope;
|
|
10
|
+
|
|
11
|
+
public async setup() {
|
|
12
|
+
const key = this.getAttributeValue() || null;
|
|
13
|
+
if (key) {
|
|
14
|
+
this.scopeRef = this.tag.scope.getReference(key, true);
|
|
15
|
+
const parentScope = await this.scopeRef.getScope();
|
|
16
|
+
const styleKey = await this.scopeRef.getKey();
|
|
17
|
+
this.styleScope = parentScope.get(styleKey);
|
|
18
|
+
if (!this.styleScope) {
|
|
19
|
+
this.styleScope = new Scope(parentScope);
|
|
20
|
+
parentScope.set(styleKey, this.styleScope);
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
this.styleScope = this.tag.scope;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await super.setup();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async connect() {
|
|
30
|
+
this.styleScope.bind(`change`, this.handleEvent.bind(this));
|
|
31
|
+
await super.connect();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async extract() {
|
|
35
|
+
this.updateFrom();
|
|
36
|
+
this.updateTo();
|
|
37
|
+
await super.extract();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
updateFrom() {
|
|
41
|
+
const toSkip = [
|
|
42
|
+
'cssText',
|
|
43
|
+
'getPropertyPriority',
|
|
44
|
+
'getPropertyValue',
|
|
45
|
+
'removeProperty',
|
|
46
|
+
'setProperty',
|
|
47
|
+
'length'
|
|
48
|
+
];
|
|
49
|
+
for (const k in this.tag.style) {
|
|
50
|
+
if (toSkip.indexOf(k) > -1 || isFinite(k as any))
|
|
51
|
+
continue;
|
|
52
|
+
const value = this.tag.style[k];
|
|
53
|
+
const key = `$${k}`;
|
|
54
|
+
if (value && value !== this.styleScope.get(key))
|
|
55
|
+
this.styleScope.set(key, value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public updateTo() {
|
|
60
|
+
for (const k of this.styleScope.keys) {
|
|
61
|
+
const v = this.styleScope.get(k);
|
|
62
|
+
if (k.startsWith('$')) {
|
|
63
|
+
const key = k.substr(1);
|
|
64
|
+
this.tag.element.style[key] = v.value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public mutate(mutation: MutationRecord) {
|
|
70
|
+
super.mutate(mutation);
|
|
71
|
+
this.updateFrom();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public async handleEvent(k, v) {
|
|
75
|
+
if (k.startsWith('$')) {
|
|
76
|
+
const key = k.substr(1);
|
|
77
|
+
|
|
78
|
+
if (v.value !== v.previousValue) {
|
|
79
|
+
this.tag.element.style[key] = v.value;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -23,5 +23,6 @@ export {ScopeAttribute} from "./ScopeAttribute";
|
|
|
23
23
|
export {ScopeChange} from "./ScopeChange";
|
|
24
24
|
export {SetAttribute} from "./SetAttribute";
|
|
25
25
|
export {StandardAttribute} from "./StandardAttribute";
|
|
26
|
+
export {StyleAttribute} from "./StyleAttribute";
|
|
26
27
|
export {Template} from "./Template";
|
|
27
28
|
export {TypeAttribute} from "./TypeAttribute";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {DOM} from "../../src/DOM";
|
|
2
|
+
import "../../src/Types";
|
|
3
|
+
import "../../src/attributes/_imports";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
describe('Styles', () => {
|
|
7
|
+
it("vsn-styles to just work", (done) => {
|
|
8
|
+
document.body.innerHTML = `
|
|
9
|
+
<div vsn-name="testing">
|
|
10
|
+
<span id="styling" vsn-styles="testing.styles" style="margin-top: 50px;">testing</span>
|
|
11
|
+
<span id="styling-dupe" vsn-styles="testing.styles" style="margin-top: 50px;">testing 2</span>
|
|
12
|
+
</div>
|
|
13
|
+
`;
|
|
14
|
+
const dom = new DOM(document);
|
|
15
|
+
dom.once('built', async () => {
|
|
16
|
+
const ele1 = (await dom.get('#styling'))[0];
|
|
17
|
+
const ele2 = (await dom.get('#styling-dupe'))[0];
|
|
18
|
+
const scope = ele1.scope;
|
|
19
|
+
const container = scope.get('testing');
|
|
20
|
+
const styles = container.get('styles');
|
|
21
|
+
expect(container).toBeTruthy();
|
|
22
|
+
expect(styles).toBeTruthy();
|
|
23
|
+
expect(ele1.element.style.marginTop).toBe('50px');
|
|
24
|
+
expect(ele2.element.style.marginTop).toBe('50px');
|
|
25
|
+
styles.set('$marginTop', '-50px');
|
|
26
|
+
expect(ele1.element.style.marginTop).toBe('-50px');
|
|
27
|
+
expect(ele2.element.style.marginTop).toBe('-50px');
|
|
28
|
+
done();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("$ operator should work", (done) => {
|
|
33
|
+
document.body.innerHTML = `
|
|
34
|
+
<span id="styling">testing</span>
|
|
35
|
+
`;
|
|
36
|
+
const dom = new DOM(document);
|
|
37
|
+
dom.once('built', async () => {
|
|
38
|
+
await dom.eval('?(#styling).$marginTop = "50px"');
|
|
39
|
+
expect((await dom.get('#styling'))[0].element.style.marginTop).toBe('50px');
|
|
40
|
+
done();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|