vsn 0.1.71 → 0.1.72

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.
Files changed (47) hide show
  1. package/demo/demo.html +5 -1
  2. package/demo/vsn.js +2 -2
  3. package/demo/xhr.html +27 -5
  4. package/dist/AST/ArithmeticAssignmentNode.js +1 -1
  5. package/dist/AST/ArithmeticAssignmentNode.js.map +1 -1
  6. package/dist/AST/ClassNode.d.ts +23 -7
  7. package/dist/AST/ClassNode.js +177 -48
  8. package/dist/AST/ClassNode.js.map +1 -1
  9. package/dist/AST/ElementAttributeNode.js +13 -4
  10. package/dist/AST/ElementAttributeNode.js.map +1 -1
  11. package/dist/AST/FunctionCallNode.js +2 -1
  12. package/dist/AST/FunctionCallNode.js.map +1 -1
  13. package/dist/AST/Node.d.ts +4 -1
  14. package/dist/AST/Node.js.map +1 -1
  15. package/dist/AST/ScopeMemberNode.js.map +1 -1
  16. package/dist/AST.js +3 -1
  17. package/dist/AST.js.map +1 -1
  18. package/dist/DOM.d.ts +2 -0
  19. package/dist/DOM.js +16 -3
  20. package/dist/DOM.js.map +1 -1
  21. package/dist/EventDispatcher.d.ts +1 -0
  22. package/dist/EventDispatcher.js +16 -0
  23. package/dist/EventDispatcher.js.map +1 -1
  24. package/dist/Registry.js +1 -1
  25. package/dist/Registry.js.map +1 -1
  26. package/dist/Tag/List.d.ts +1 -1
  27. package/dist/Tag/List.js +4 -14
  28. package/dist/Tag/List.js.map +1 -1
  29. package/dist/Tag.d.ts +0 -1
  30. package/dist/Tag.js +0 -1
  31. package/dist/Tag.js.map +1 -1
  32. package/dist/vsn.min.js +2 -2
  33. package/package.json +1 -1
  34. package/src/AST/ArithmeticAssignmentNode.ts +1 -1
  35. package/src/AST/ClassNode.ts +125 -33
  36. package/src/AST/ElementAttributeNode.ts +9 -4
  37. package/src/AST/FunctionCallNode.ts +2 -1
  38. package/src/AST/Node.ts +5 -1
  39. package/src/AST/ScopeMemberNode.ts +0 -1
  40. package/src/AST.ts +3 -1
  41. package/src/DOM.ts +15 -3
  42. package/src/EventDispatcher.ts +8 -0
  43. package/src/Registry.ts +1 -1
  44. package/src/Tag/List.ts +5 -13
  45. package/src/Tag.ts +0 -1
  46. package/test/AST/ClassNode.spec.ts +40 -11
  47. package/test/attributes/ListItem.spec.ts +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vsn",
3
- "version": "0.1.71",
3
+ "version": "0.1.72",
4
4
  "description": "SEO Friendly Javascript/Typescript Framework",
5
5
  "keywords": [
6
6
  "framework",
@@ -48,7 +48,7 @@ export class ArithmeticAssignmentNode extends Node implements TreeNode {
48
48
  }
49
49
  } else if ((this.left instanceof ElementAttributeNode || this.left instanceof ElementStyleNode) && this.left.elementRef) {
50
50
  const elements = await this.left.elementRef.evaluate(scope, dom, tag);
51
- if (this.left.elementRef.first) {
51
+ if (this.left.elementRef.first || elements instanceof DOMObject) {
52
52
  scopes.push(elements);
53
53
  } else {
54
54
  scopes = elements;
@@ -2,45 +2,76 @@ import {Scope} from "../Scope";
2
2
  import {DOM} from "../DOM";
3
3
  import {Tag} from "../Tag";
4
4
  import {Token, TokenType, Tree, TreeNode} from "../AST";
5
- import {Node} from "./Node";
5
+ import {INodeMeta, Node} from "./Node";
6
6
  import {BlockNode} from "./BlockNode";
7
7
  import {Registry} from "../Registry";
8
8
  import {OnNode} from "./OnNode";
9
9
  import {FunctionNode} from "./FunctionNode";
10
10
 
11
11
  export class ClassNode extends Node implements TreeNode {
12
+ public static readonly ClassesVariable = '_vsn_classes';
12
13
  public static readonly classes: {[name: string]: ClassNode} = {};
14
+ public static readonly classParents: {[name: string]: string[]} = {};
15
+ public static readonly classChildren: {[name: string]: string[]} = {}; // List of child class selectors for a given class selector
16
+ public static readonly preppedTags: {[name: string]: Tag[]} = {};
17
+
13
18
  protected requiresPrep: boolean = true;
14
19
  public readonly classScope: Scope = new Scope();
15
- protected _ready: boolean = false;
20
+ protected _fullSelector: string;
16
21
 
17
22
  constructor(
18
- public readonly name: string,
23
+ public readonly selector: string,
19
24
  public readonly block: BlockNode
20
25
  ) {
21
26
  super();
22
27
  }
23
28
 
29
+ public get fullSelector(): string {
30
+ return this._fullSelector;
31
+ }
32
+
24
33
  public updateMeta(meta?: any) {
25
34
  meta = meta || {};
26
35
  meta['ClassNode'] = this;
27
36
  return meta;
28
37
  }
29
38
 
30
- public async prepare(scope: Scope, dom: DOM, tag: Tag = null, meta?: any): Promise<void> {
31
- meta = meta || {};
32
- meta['ClassNodePrepare'] = true;
33
- if (ClassNode.classes[this.name]) return; // Don't re-prepare same classes
34
- ClassNode.classes[this.name] = this;
35
- await this.block.prepare(this.classScope, dom, tag, meta);
36
- Registry.class(this);
37
-
38
- for (const element of Array.from(dom.querySelectorAll(`.${this.name}`))) {
39
- await ClassNode.checkForClassChanges(element as HTMLElement, dom, element[Tag.TaggedVariable] || null);
39
+ public async prepare(scope: Scope, dom: DOM, tag: Tag = null, meta?: INodeMeta): Promise<void> {
40
+ meta = Object.assign({}, meta) || {};
41
+ const initial = !!meta['initial'];
42
+ meta['ClassNodePrepare'] = initial;
43
+
44
+ // Only prepare once during the initial prep, all subsequent prepares are on tag class blocks
45
+ if (initial) {
46
+ if (meta['ClassNodeSelector']) {
47
+ ClassNode.classChildren[meta['ClassNodeSelector'] as string].push(this.selector);
48
+ meta['ClassNodeSelector'] = `${meta['ClassNodeSelector']} ${this.selector}`;
49
+ } else {
50
+ meta['ClassNodeSelector'] = this.selector;
51
+ }
52
+
53
+ this._fullSelector = meta['ClassNodeSelector'];
54
+ if (ClassNode.classes[this._fullSelector]) return; // Don't re-prepare same classes
55
+ ClassNode.classes[this._fullSelector] = this;
56
+ ClassNode.classChildren[this._fullSelector] = [];
57
+ ClassNode.preppedTags[this._fullSelector] = [];
58
+
59
+ if (ClassNode.classParents[this.selector] === undefined)
60
+ ClassNode.classParents[this.selector] = [];
61
+
62
+ ClassNode.classParents[this.selector].push(this._fullSelector);
63
+ await this.block.prepare(this.classScope, dom, tag, meta);
64
+ Registry.class(this);
65
+
66
+ for (const element of Array.from(dom.querySelectorAll(this._fullSelector))) {
67
+ await ClassNode.addElementClass(this._fullSelector, element as HTMLElement, dom, element[Tag.TaggedVariable] || null);
68
+ }
69
+ } else {
70
+ await this.block.prepare(this.classScope, dom, tag, meta);
40
71
  }
41
72
  }
42
73
 
43
- public async prepareTag(tag: Tag, dom: DOM, hasConstructor: boolean | null = null) {
74
+ public async constructTag(tag: Tag, dom: DOM, hasConstructor: boolean | null = null) {
44
75
  if (hasConstructor === null)
45
76
  hasConstructor = this.classScope.has('construct');
46
77
 
@@ -52,10 +83,12 @@ export class ClassNode extends Node implements TreeNode {
52
83
  const fnc = await fncCls.getFunction(tag.scope, dom, tag, false);
53
84
  await fnc();
54
85
  }
55
- tag.preppedClasses.push(this.name);
86
+ tag.dispatch(`${this.fullSelector}.construct`, tag.element.id);
87
+ ClassNode.preppedTags[this.fullSelector].push(tag);
88
+ ClassNode.addPreparedClassToElement(tag.element, this.fullSelector);
56
89
  }
57
90
 
58
- public async tearDownTag(tag: Tag, dom: DOM, hasDeconstructor: boolean | null = null) {
91
+ public async deconstructTag(tag: Tag, dom: DOM, hasDeconstructor: boolean | null = null) {
59
92
  if (hasDeconstructor === null)
60
93
  hasDeconstructor = this.classScope.has('deconstruct');
61
94
 
@@ -70,7 +103,9 @@ export class ClassNode extends Node implements TreeNode {
70
103
  tag.removeContextEventHandlers(on);
71
104
  }
72
105
  }
73
- tag.preppedClasses.splice(tag.preppedClasses.indexOf(this.name), 1);
106
+ tag.dispatch(`${this.fullSelector}.deconstruct`);
107
+ ClassNode.preppedTags[this.fullSelector].splice(ClassNode.preppedTags[this.fullSelector].indexOf(tag), 1);
108
+ await ClassNode.removePreparedClassFromElement(tag.element, this.fullSelector);
74
109
  }
75
110
 
76
111
  public async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
@@ -84,35 +119,92 @@ export class ClassNode extends Node implements TreeNode {
84
119
  if (t.type === TokenType.L_BRACE) break;
85
120
  nameParts.push(t.value);
86
121
  }
87
- const name = nameParts.join('').trim();
122
+ const selector = nameParts.join('').trim();
88
123
  tokens.splice(0, nameParts.length);
89
124
  const block = Tree.processTokens(Tree.getNextStatementTokens(tokens, true, true));
90
- return new ClassNode(name, block);
125
+ return new ClassNode(selector, block);
91
126
  }
92
127
 
93
128
  public static async checkForClassChanges(element: HTMLElement, dom: DOM, tag: Tag = null) {
94
- const classes: string[] = Array.from(element.classList);
95
- let addedClasses: string[] = classes.filter(c => Registry.instance.classes.has(c));
96
- let removedClasses: string[];
129
+ const localSelectors: string[] = [element.tagName.toLowerCase(), ...Array.from(element.classList).map(c => `.${c}`)];
130
+ const fullSelectors: string[] = [...ClassNode.getClassesForElement(element)];
131
+ if (element.id)
132
+ localSelectors.push(`#${element.id}`);
133
+
134
+ for (const selector in localSelectors) {
135
+ if (ClassNode.classParents[selector])
136
+ fullSelectors.push(...ClassNode.classParents[selector]);
137
+ }
97
138
 
98
139
  if (!tag) {
99
140
  tag = await dom.getTagForElement(element, true);
100
141
  }
101
- addedClasses = addedClasses.filter(c => !tag.preppedClasses.includes(c));
102
- removedClasses = tag.preppedClasses.filter(c => !classes.includes(c));
103
142
 
104
- for (const addedClass of addedClasses) {
105
- const classNode: ClassNode = Registry.instance.classes.getSynchronous(addedClass);
106
- if (classNode) {
107
- await classNode.prepareTag(tag, dom);
143
+ for (const selector of fullSelectors) {
144
+ const isPrepped = ClassNode.getClassesForElement(element).includes(selector);
145
+ const elements = Array.from(dom.querySelectorAll(selector));
146
+ const inElements = elements.includes(element);
147
+ let changed: boolean = false;
148
+
149
+ if (inElements && !isPrepped) {
150
+ await ClassNode.addElementClass(selector, element, dom, tag);
151
+ changed = true;
152
+ } else if (!inElements && isPrepped) {
153
+ await ClassNode.removeElementClass(selector, element, dom, tag);
154
+ changed = true;
108
155
  }
109
- }
110
156
 
111
- for (const removedClass of removedClasses) {
112
- const classNode: ClassNode = Registry.instance.classes.getSynchronous(removedClass);
113
- if (classNode) {
114
- await classNode.tearDownTag(tag, dom);
157
+ if (changed && ClassNode.classChildren[selector].length > 0) {
158
+ for (const childSelector of ClassNode.classChildren[selector]) {
159
+ for (const childElement of Array.from(dom.querySelectorAll(childSelector, tag)) as HTMLElement[]) {
160
+ await ClassNode.checkForClassChanges(childElement, dom, childElement[Tag.TaggedVariable] || null);
161
+ }
162
+ }
115
163
  }
164
+
165
+ }
166
+ }
167
+
168
+ public static getClassesForElement(element: HTMLElement): string[] {
169
+ if (!element[ClassNode.ClassesVariable])
170
+ element[ClassNode.ClassesVariable] = [];
171
+ return element[ClassNode.ClassesVariable];
172
+ }
173
+
174
+ public static addPreparedClassToElement(element: HTMLElement, selector: string) {
175
+ ClassNode.getClassesForElement(element).push(selector);
176
+ }
177
+
178
+ public static removePreparedClassFromElement(element: HTMLElement, selector: string) {
179
+ const classes = ClassNode.getClassesForElement(element);
180
+ classes.splice(classes.indexOf(selector), 1);
181
+ }
182
+
183
+ public static async addElementClass(selector: string, element: HTMLElement, dom: DOM, tag: Tag = null) {
184
+ const classes = ClassNode.getClassesForElement(element);
185
+ if (classes.includes(selector)) return;
186
+
187
+ if (!tag) {
188
+ tag = await dom.getTagForElement(element, true);
189
+ }
190
+
191
+ const classNode: ClassNode = Registry.instance.classes.getSynchronous(selector);
192
+ if (classNode) {
193
+ await classNode.constructTag(tag, dom);
194
+ }
195
+ }
196
+
197
+ public static async removeElementClass(selector: string, element: HTMLElement, dom: DOM, tag: Tag = null) {
198
+ const classes = ClassNode.getClassesForElement(element);
199
+ if (!classes.includes(selector)) return;
200
+
201
+ if (!tag) {
202
+ tag = await dom.getTagForElement(element, true);
203
+ }
204
+
205
+ const classNode: ClassNode = Registry.instance.classes.getSynchronous(selector);
206
+ if (classNode) {
207
+ await classNode.deconstructTag(tag, dom);
116
208
  }
117
209
  }
118
210
 
@@ -6,6 +6,7 @@ import {TreeNode} from "../AST";
6
6
  import {Node} from "./Node";
7
7
  import {ElementQueryNode} from "./ElementQueryNode";
8
8
  import {LiteralNode} from "./LiteralNode";
9
+ import {DOMObject} from "../DOM/DOMObject";
9
10
 
10
11
  export class ElementAttributeNode extends Node implements TreeNode {
11
12
  protected requiresPrep: boolean = true;
@@ -53,10 +54,14 @@ export class ElementAttributeNode extends Node implements TreeNode {
53
54
  async prepare(scope: Scope, dom: DOM, tag: Tag = null, meta: any = null) {
54
55
  if (this.elementRef) {
55
56
  await this.elementRef.prepare(scope, dom, tag, meta);
56
- const tags: TagList = await this.elementRef.evaluate(scope, dom, tag, true);
57
- for (const t of tags)
58
- await t.watchAttribute(this.attributeName);
59
- } else if(tag) {
57
+ const tags: any = await this.elementRef.evaluate(scope, dom, tag, true);
58
+ if (tags instanceof TagList) {
59
+ for (const t of tags)
60
+ await t.watchAttribute(this.attributeName);
61
+ } else if (tags instanceof DOMObject) {
62
+ await (tags as DOMObject).watchAttribute(this.attributeName);
63
+ }
64
+ } else if (tag) {
60
65
  await tag.watchAttribute(this.attributeName);
61
66
  }
62
67
  }
@@ -8,6 +8,7 @@ import {ScopeMemberNode} from "./ScopeMemberNode";
8
8
  import {FunctionNode} from "./FunctionNode";
9
9
  import {Registry} from "../Registry";
10
10
  import {ElementQueryNode} from "./ElementQueryNode";
11
+ import {ClassNode} from "./ClassNode";
11
12
 
12
13
  export class FunctionCallNode<T = any> extends Node implements TreeNode {
13
14
  constructor(
@@ -46,7 +47,7 @@ export class FunctionCallNode<T = any> extends Node implements TreeNode {
46
47
  let calls = 0;
47
48
  for (const _tag of tags) {
48
49
  let tagNum = 0;
49
- for (const className of _tag.preppedClasses) {
50
+ for (const className of _tag.element[ClassNode.ClassesVariable]) {
50
51
  tagNum++;
51
52
  const cls = Registry.instance.classes.getSynchronous(className);
52
53
  if (cls) {
package/src/AST/Node.ts CHANGED
@@ -3,6 +3,10 @@ import {DOM} from "../DOM";
3
3
  import {Tag} from "../Tag";
4
4
  import {TreeNode} from "../AST";
5
5
 
6
+ export interface INodeMeta {
7
+ [key: string]: string | number | boolean | null;
8
+ }
9
+
6
10
  export abstract class Node implements TreeNode {
7
11
  protected requiresPrep: boolean = false;
8
12
  protected _isPreparationRequired: boolean;
@@ -28,7 +32,7 @@ export abstract class Node implements TreeNode {
28
32
  return false;
29
33
  }
30
34
 
31
- async prepare(scope: Scope, dom: DOM, tag: Tag = null, meta: any = null): Promise<void> {
35
+ async prepare(scope: Scope, dom: DOM, tag: Tag = null, meta: INodeMeta = null): Promise<void> {
32
36
  for (const node of this.getChildNodes()) {
33
37
  await node.prepare(scope, dom, tag, meta);
34
38
  }
@@ -26,7 +26,6 @@ export class ScopeMemberNode extends ScopeNodeAbstract implements TreeNode {
26
26
  async evaluate(scope: Scope, dom: DOM, tag: Tag = null) {
27
27
  let scopes = [];
28
28
  const values = [];
29
-
30
29
  if (this.scope instanceof ElementQueryNode) {
31
30
  const elements = await this.scope.evaluate(scope, dom, tag);
32
31
  if (this.scope.first) {
package/src/AST.ts CHANGED
@@ -420,7 +420,9 @@ export class Tree {
420
420
  async prepare(scope: Scope, dom: DOM, tag: Tag = null) {
421
421
  if (!this._root.isPreparationRequired())
422
422
  return;
423
- return await this._root.prepare(scope, dom, tag);
423
+ return await this._root.prepare(scope, dom, tag, {
424
+ initial: true
425
+ });
424
426
  }
425
427
 
426
428
  async bindToScopeChanges(scope, fnc, dom: DOM, tag: Tag = null) {
package/src/DOM.ts CHANGED
@@ -18,6 +18,7 @@ export enum EQuerySelectDirection {
18
18
  export class DOM extends EventDispatcher {
19
19
  protected static _instance: DOM;
20
20
  protected _root: Tag;
21
+ protected _ready: Promise<boolean>;
21
22
  protected tags: Tag[];
22
23
  protected observer: MutationObserver;
23
24
  protected evaluateTimeout: any;
@@ -32,6 +33,12 @@ export class DOM extends EventDispatcher {
32
33
  protected debug: boolean = false
33
34
  ) {
34
35
  super();
36
+ this._ready = new Promise((resolve) => {
37
+ this.once('built', () => {
38
+ resolve(true);
39
+ });
40
+ });
41
+
35
42
  this.observer = new MutationObserver(this.mutation.bind(this));
36
43
  this.tags = [];
37
44
 
@@ -49,6 +56,10 @@ export class DOM extends EventDispatcher {
49
56
  return this._root;
50
57
  }
51
58
 
59
+ public get ready(): Promise<boolean> {
60
+ return
61
+ }
62
+
52
63
  public async get(selector: string, create: boolean = false, tag: Tag = null, direction: EQuerySelectDirection = EQuerySelectDirection.DOWN): Promise<TagList> {
53
64
  switch (selector) {
54
65
  case 'window':
@@ -232,7 +243,7 @@ export class DOM extends EventDispatcher {
232
243
  const found: Element[] = [];
233
244
  for (const tag of this.tags)
234
245
  {
235
- if (elements.indexOf(tag.element) > -1) {
246
+ if (!found.includes(tag.element) && elements.indexOf(tag.element) > -1) {
236
247
  tags.push(tag);
237
248
  found.push(tag.element);
238
249
  }
@@ -242,8 +253,9 @@ export class DOM extends EventDispatcher {
242
253
  const notFound: Element[] = [...elements];
243
254
  for (let i = notFound.length; i >= 0; i--) {
244
255
  const element: Element = notFound[i];
245
- if (found.indexOf(element) > -1)
246
- notFound.pop();
256
+ if (found.indexOf(element) > -1) {
257
+ notFound.splice(i, 1);
258
+ }
247
259
  }
248
260
 
249
261
  for (const element of notFound) {
@@ -70,6 +70,14 @@ export class EventDispatcher {
70
70
  return this.on(event, fct, context, true);
71
71
  }
72
72
 
73
+ promise(event: string, ...args: any[]): Promise<any> {
74
+ return new Promise((resolve, reject) => {
75
+ this.once(event, (...args) => {
76
+ resolve(args);
77
+ }, null);
78
+ });
79
+ }
80
+
73
81
  off(event: string, key?: number): boolean {
74
82
  if(!(event in this._listeners)) return false;
75
83
  if(key) {
package/src/Registry.ts CHANGED
@@ -90,7 +90,7 @@ export class Registry extends EventDispatcher {
90
90
  }
91
91
 
92
92
  public static class(cls: ClassNode) {
93
- Registry.instance.classes.register(cls.name, cls);
93
+ Registry.instance.classes.register(cls.fullSelector, cls);
94
94
  }
95
95
 
96
96
  public static controller(key: string = null, setup = null) {
package/src/Tag/List.ts CHANGED
@@ -12,19 +12,6 @@ export class TagList extends Array<DOMObject> {
12
12
  return this[0].scope
13
13
  }
14
14
 
15
- on(event, cbOrSelector, cb) {
16
- if (typeof cbOrSelector === "function") {
17
- this.forEach(e => e.element.addEventListener(event, cbOrSelector))
18
- } else {
19
- this.forEach(elem => {
20
- elem.element.addEventListener(event, e => {
21
- if (e.target.matches(cbOrSelector)) cb(e)
22
- })
23
- })
24
- }
25
- return this
26
- }
27
-
28
15
  get elements(): HTMLElement[] {
29
16
  return this.map(e => e.element);
30
17
  }
@@ -37,6 +24,11 @@ export class TagList extends Array<DOMObject> {
37
24
  return this[this.length - 1];
38
25
  }
39
26
 
27
+ all(event: string): Promise<number[]> {
28
+ const promises = this.map(e => e.promise(event));
29
+ return Promise.all(promises);
30
+ }
31
+
40
32
  removeClass(className) {
41
33
  this.forEach(e => e.element.classList.remove(className))
42
34
  return this
package/src/Tag.ts CHANGED
@@ -26,7 +26,6 @@ export class Tag extends DOMObject {
26
26
  public readonly rawAttributes: { [key: string]: string; };
27
27
  public readonly parsedAttributes: { [key: string]: string[]; };
28
28
  public readonly deferredAttributes: Attribute[] = [];
29
- public readonly preppedClasses: string[] = [];
30
29
  protected _state: TagState;
31
30
  protected attributes: Attribute[];
32
31
  protected _nonDeferredAttributes: Attribute[] = [];
@@ -1,29 +1,58 @@
1
1
  import {DOM} from "../../src/DOM";
2
+ import {ClassNode} from "../../src/AST/ClassNode";
3
+ import {Registry} from "../../src/Registry";
4
+ import {TagList} from "../../src/Tag/List";
2
5
 
3
6
 
4
7
  describe('ClassNode', () => {
5
- it("properly define a simple class", (done) => {
8
+ it("properly combine nested classes", async () => {
6
9
  document.body.innerHTML = `
7
10
  <script type="text/vsn" vsn-script>
8
- class simple {
11
+ class .simple {
12
+ func construct() {}
13
+ class input {
14
+ func construct() {}
15
+ }
16
+ }
17
+ </script>
18
+ <div class="simple"><input /></div>
19
+ `;
20
+ const dom = new DOM(document);
21
+ await dom.ready;
22
+ await Registry.instance.classes.get('.simple input');
23
+ expect(ClassNode.classParents['input']).toBeInstanceOf(Array);
24
+ expect(ClassNode.classParents['input'].includes('.simple input')).toBe(true);
25
+ expect(ClassNode.classes['.simple input']).toBeInstanceOf(ClassNode);
26
+ });
27
+
28
+ it("properly define a simple class", async () => {
29
+ document.body.innerHTML = `
30
+ <script type="text/vsn" vsn-script>
31
+ class .simple-construct {
9
32
  func construct() {
10
- a|integer = "15";
33
+ a|integer = "15";
34
+ log('####### construct', a);
11
35
  }
12
36
 
13
37
  func test() {
14
38
  a += 1;
39
+ log('####### testing', a);
15
40
  }
16
41
  }
17
42
  </script>
18
- <div class="simple"></div>
19
- <div class="simple"></div>
43
+ <div class="simple-construct" id="ele-1"></div>
44
+ <div class="simple-construct" id="ele-2"></div>
20
45
  `;
21
46
  const dom = new DOM(document);
22
- dom.once('built', async () => {
23
- expect(await dom.exec('?(.simple).a')).toEqual([15, 15]);
24
- await dom.exec('?(.simple).test()');
25
- expect(await dom.exec('?(.simple).a')).toEqual([16, 16]);
26
- done();
27
- });
47
+ await dom.ready;
48
+ await Registry.instance.classes.get('.simple-construct');
49
+ const t: TagList = await dom.exec('?(.simple-construct)');
50
+ expect(t).toBeInstanceOf(TagList);
51
+ expect(t.length).toBe(2);
52
+ await t.all('.simple-construct.construct');
53
+ console.log('####### hmm?', await dom.exec('?(.simple-construct).a'));
54
+ expect(await dom.exec('?(.simple-construct).a')).toEqual([15, 15]);
55
+ await dom.exec('?(.simple-construct).test()');
56
+ expect(await dom.exec('?(.simple-construct).a')).toEqual([16, 16]);
28
57
  });
29
58
  });
@@ -68,7 +68,6 @@ describe('ListItem', () => {
68
68
  </ul>
69
69
  </div>
70
70
  `;
71
- console.log('########### test');
72
71
  const dom = new DOM(document);
73
72
  dom.once('built', async () => {
74
73
  const list = await dom.getTagForElement(document.getElementById('test'));