vsn 0.1.51 → 0.1.54

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 CHANGED
@@ -1,3 +1,5 @@
1
+ [![npm version](https://badge.fury.io/js/vsn.svg)](https://badge.fury.io/js/vsn) [![Build Status](https://travis-ci.org/malero/vsn.svg?branch=master)](https://travis-ci.org/malero/vsn) [![codecov](https://codecov.io/gh/malero/vsn/branch/master/graph/badge.svg)](https://codecov.io/gh/malero/vsn) [![npm](https://img.shields.io/npm/dw/vsn.svg)]() [![gzip bundle size](http://img.badgesize.io/https://unpkg.com/vsn@latest/dist/?compression=gzip&style=flat-square)](https://unpkg.com/vsn)
2
+
1
3
  # VisionJS Framework
2
4
 
3
5
  Simple Javascript Framework built from the ground up with eCommerce and SEO in mind. VisionJS is meant to be used with server side rendered websites. Rather than dynamically rendering component templates like most javascript frameworks, VisionJS uses the html rendered by your server to add functionality to your website.
@@ -8,60 +10,6 @@ Use NPM to install VisionJS with the following command:
8
10
  npm i vsn
9
11
 
10
12
 
11
- ## Examples
12
- ### Set A Scope Variable
13
- Use `vsn-set:variable_name="value|type"` to set a variable in the scope. `vsn-set` is only used to initialize a value and will only be evaluated once. Use `vsn-bind` if you would like to bind the element to the scope variable.
14
-
15
- <div vsn-set:my_string="42"></div>
16
- <div vsn-set:my_int="42|int"></div>
17
- <div vsn-set:my_float="42.3|float"></div>
18
- <div vsn-set:my_bool="false|bool"></div>
19
-
20
-
21
- ### Attribute Binding
22
- Use `vsn-bind:attribute` to bind a scope variable to the element's attribute. Using `vsn-bind` on an input will bind the input's value to the scope variable.
23
-
24
- <a href="/index.html" id="link">Home</a>
25
- <input type="text" vsn-bind="#link.@text" />
26
- <input type="text" vsn-bind="#link.@href" />
27
-
28
-
29
- ### Bind to Element Events
30
- Use `vsn-on` on an element to execute some code when the specified event is triggered. Here we have a button that toggles the root scope variable `show` between false and true when the element is clicked.
31
-
32
- <button vsn-on:click="show = !show" vsn-set:show="false|bool">Toggle</button>
33
- <span vsn-bind="show"></span>
34
-
35
-
36
- ### Conditional Elements
37
- Use `vsn-if` if you would only like to show an element if a certain condition is met.
38
-
39
- <button vsn-on:click="show = !show" vsn-set:show="false|bool">Toggle</button>
40
- <span vsn-if="show">Show is true</span>
41
- <span vsn-if="!show">Show is false</span>
42
-
43
-
44
- ### Controllers
45
- Use `vsn-controller:variable_name="ClassName"` to bind an element to a controller class.
46
-
47
- Typescript class controller:
48
-
49
- class Controller {
50
- public on: boolean = false;
51
-
52
- doSomething($event, value) {
53
- $event.preventDefault();
54
- this.on = value;
55
- }
56
- }
57
- vision.registerClass(Controller, 'Controller');
58
-
59
- HTML to use the above controller:
60
-
61
- <div vsn-controller:controller="Controller">
62
- <span vsn-if="controller.on">It's on!</span>
63
- <span vsn-if="!controller.on">It's off...</span>
64
- <a href="/" vsn-on:click="controller.doSomething($event, !controller.on)">Click Me</a>
65
- </div>
13
+ ## Usage
66
14
 
67
- Note: `variable_name` cannot contain capitalized letters. Use `<tag vsn-controller="ClassName" vsn-name="variableName" />` if you need to use capitalized letters in your controller name.
15
+ Please visit the [docs](https://www.vsnjs.org) for more information.
@@ -1,5 +1,9 @@
1
1
  import { Attribute } from "../Attribute";
2
+ import { Tree } from "../AST";
2
3
  export declare class ScopeAttribute extends Attribute {
3
4
  static readonly canDefer: boolean;
4
5
  static readonly scoped: boolean;
6
+ protected tree: Tree;
7
+ compile(): Promise<void>;
8
+ extract(): Promise<void>;
5
9
  }
@@ -20,15 +20,90 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
20
20
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
21
  return c > 3 && r && Object.defineProperty(target, key, r), r;
22
22
  };
23
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
24
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
25
+ return new (P || (P = Promise))(function (resolve, reject) {
26
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
27
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
28
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
29
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
30
+ });
31
+ };
32
+ var __generator = (this && this.__generator) || function (thisArg, body) {
33
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
34
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
35
+ function verb(n) { return function (v) { return step([n, v]); }; }
36
+ function step(op) {
37
+ if (f) throw new TypeError("Generator is already executing.");
38
+ while (_) try {
39
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
40
+ if (y = 0, t) op = [op[0] & 2, t.value];
41
+ switch (op[0]) {
42
+ case 0: case 1: t = op; break;
43
+ case 4: _.label++; return { value: op[1], done: false };
44
+ case 5: _.label++; y = op[1]; op = [0]; continue;
45
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
46
+ default:
47
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
48
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
49
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
50
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
51
+ if (t[2]) _.ops.pop();
52
+ _.trys.pop(); continue;
53
+ }
54
+ op = body.call(thisArg, _);
55
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
56
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
57
+ }
58
+ };
23
59
  Object.defineProperty(exports, "__esModule", { value: true });
24
60
  exports.ScopeAttribute = void 0;
25
61
  var Attribute_1 = require("../Attribute");
26
62
  var Registry_1 = require("../Registry");
63
+ var AST_1 = require("../AST");
64
+ var Scope_1 = require("../Scope");
27
65
  var ScopeAttribute = /** @class */ (function (_super) {
28
66
  __extends(ScopeAttribute, _super);
29
67
  function ScopeAttribute() {
30
68
  return _super !== null && _super.apply(this, arguments) || this;
31
69
  }
70
+ ScopeAttribute.prototype.compile = function () {
71
+ return __awaiter(this, void 0, void 0, function () {
72
+ return __generator(this, function (_a) {
73
+ switch (_a.label) {
74
+ case 0:
75
+ this.tree = new AST_1.Tree(this.getAttributeValue());
76
+ return [4 /*yield*/, this.tree.prepare(this.tag.scope, this.tag.dom, this.tag)];
77
+ case 1:
78
+ _a.sent();
79
+ return [4 /*yield*/, _super.prototype.compile.call(this)];
80
+ case 2:
81
+ _a.sent();
82
+ return [2 /*return*/];
83
+ }
84
+ });
85
+ });
86
+ };
87
+ ScopeAttribute.prototype.extract = function () {
88
+ return __awaiter(this, void 0, void 0, function () {
89
+ var value, _i, _a, key;
90
+ return __generator(this, function (_b) {
91
+ switch (_b.label) {
92
+ case 0: return [4 /*yield*/, this.tree.evaluate(this.tag.scope, this.tag.dom, this.tag)];
93
+ case 1:
94
+ value = _b.sent();
95
+ if (!(value instanceof Scope_1.Scope)) {
96
+ throw new Error("Scope value must be an object, got " + typeof value);
97
+ }
98
+ for (_i = 0, _a = value.data.keys; _i < _a.length; _i++) {
99
+ key = _a[_i];
100
+ this.tag.scope.set(key, value.data[key]);
101
+ }
102
+ return [2 /*return*/];
103
+ }
104
+ });
105
+ });
106
+ };
32
107
  ScopeAttribute.canDefer = false;
33
108
  ScopeAttribute.scoped = true;
34
109
  ScopeAttribute = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"ScopeAttribute.js","sourceRoot":"","sources":["../../src/attributes/ScopeAttribute.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,0CAAuC;AACvC,wCAAqC;AAGrC;IAAoC,kCAAS;IAA7C;;IAGA,CAAC;IAF0B,uBAAQ,GAAY,KAAK,CAAC;IAC1B,qBAAM,GAAY,IAAI,CAAC;IAFrC,cAAc;QAD1B,mBAAQ,CAAC,SAAS,CAAC,WAAW,CAAC;OACnB,cAAc,CAG1B;IAAD,qBAAC;CAAA,AAHD,CAAoC,qBAAS,GAG5C;AAHY,wCAAc"}
1
+ {"version":3,"file":"ScopeAttribute.js","sourceRoot":"","sources":["../../src/attributes/ScopeAttribute.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0CAAuC;AACvC,wCAAqC;AACrC,8BAA4B;AAC5B,kCAA+B;AAG/B;IAAoC,kCAAS;IAA7C;;IAoBA,CAAC;IAfgB,gCAAO,GAApB;;;;;wBACI,IAAI,CAAC,IAAI,GAAG,IAAI,UAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC;wBAC/C,qBAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAAA;;wBAA/D,SAA+D,CAAC;wBAChE,qBAAM,iBAAM,OAAO,WAAE,EAAA;;wBAArB,SAAqB,CAAC;;;;;KACzB;IAEY,gCAAO,GAApB;;;;;4BACkB,qBAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAAA;;wBAAxE,KAAK,GAAG,SAAgE;wBAC9E,IAAI,CAAC,CAAC,KAAK,YAAY,aAAK,CAAC,EAAE;4BAC3B,MAAM,IAAI,KAAK,CAAC,wCAAsC,OAAO,KAAO,CAAC,CAAC;yBACzE;wBACD,WAAiC,EAAf,KAAA,KAAK,CAAC,IAAI,CAAC,IAAI,EAAf,cAAe,EAAf,IAAe,EAAE;4BAAxB,GAAG;4BACV,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;yBAC5C;;;;;KACJ;IAlBsB,uBAAQ,GAAY,KAAK,CAAC;IAC1B,qBAAM,GAAY,IAAI,CAAC;IAFrC,cAAc;QAD1B,mBAAQ,CAAC,SAAS,CAAC,WAAW,CAAC;OACnB,cAAc,CAoB1B;IAAD,qBAAC;CAAA,AApBD,CAAoC,qBAAS,GAoB5C;AApBY,wCAAc"}
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "vsn",
3
- "version": "0.1.51",
3
+ "version": "0.1.54",
4
4
  "description": "SEO Friendly Javascript/Typescript Framework",
5
5
  "keywords": [
6
6
  "framework",
7
- "typescript"
7
+ "typescript",
8
+ "html",
9
+ "ajax",
10
+ "hateoas",
11
+ "rest",
12
+ "seo"
8
13
  ],
9
14
  "main": "./dist/vsn.js",
10
15
  "scripts": {
package/src/Tag.ts CHANGED
@@ -250,6 +250,9 @@ export class Tag extends DOMObject {
250
250
  if (!!this._scope)
251
251
  return this._scope;
252
252
 
253
+ if (this.uniqueScope)
254
+ return this.createScope();
255
+
253
256
  if (!!this._parentTag)
254
257
  return this._parentTag.scope;
255
258
 
@@ -432,7 +435,6 @@ export class Tag extends DOMObject {
432
435
 
433
436
  if (requiresScope && !this.uniqueScope) {
434
437
  this._uniqueScope = true;
435
- this._scope = new Scope();
436
438
  }
437
439
 
438
440
  this._state = TagState.AttributesBuilt;
@@ -569,17 +571,21 @@ export class Tag extends DOMObject {
569
571
  }
570
572
  }
571
573
 
572
- public createScope() {
574
+ public createScope(force: boolean = false): Scope {
573
575
  // Standard attribute requires a unique scope
574
576
  // @todo: Does this cause any issues with attribute bindings on the parent scope prior to having its own scope? hmm...
575
- if (!this.uniqueScope) {
577
+ if ((!this.uniqueScope && force) || this.uniqueScope) {
576
578
  this._uniqueScope = true;
577
579
  this._scope = new Scope();
578
580
 
579
581
  if (this.parentTag) {
580
582
  this.scope.parentScope = this.parentTag.scope;
581
583
  }
584
+
585
+ return this._scope;
582
586
  }
587
+
588
+ return null;
583
589
  }
584
590
 
585
591
  async watchAttribute(attributeName: string) {
@@ -589,7 +595,7 @@ export class Tag extends DOMObject {
589
595
  }
590
596
  }
591
597
 
592
- this.createScope();
598
+ this.createScope(true);
593
599
 
594
600
  const standardAttribute = new StandardAttribute(this, attributeName);
595
601
  this.attributes.push(standardAttribute);
@@ -605,7 +611,7 @@ export class Tag extends DOMObject {
605
611
  }
606
612
  }
607
613
 
608
- this.createScope();
614
+ this.createScope(true);
609
615
 
610
616
  const styleAttribute = new StyleAttribute(this, 'style');
611
617
  this.attributes.push(styleAttribute);
@@ -1,8 +1,33 @@
1
1
  import {Attribute} from "../Attribute";
2
2
  import {Registry} from "../Registry";
3
+ import {Tree} from "../AST";
4
+ import {Scope} from "../Scope";
3
5
 
4
6
  @Registry.attribute('vsn-scope')
5
7
  export class ScopeAttribute extends Attribute {
6
8
  public static readonly canDefer: boolean = false;
7
9
  public static readonly scoped: boolean = true;
10
+ protected tree: Tree;
11
+
12
+ public async compile() {
13
+ const code = this.getAttributeValue();
14
+ if (code) {
15
+ this.tree = new Tree(code);
16
+ await this.tree.prepare(this.tag.scope, this.tag.dom, this.tag);
17
+ }
18
+ await super.compile();
19
+ }
20
+
21
+ public async extract() {
22
+ if (this.tree) {
23
+ const value = await this.tree.evaluate(this.tag.scope, this.tag.dom, this.tag);
24
+ if (!(value instanceof Scope)) {
25
+ throw new Error(`vsn-scope value must be an object, got ${typeof value}`);
26
+ }
27
+ for (const key of value.data.keys) {
28
+ this.tag.scope.set(key, value.data[key]);
29
+ }
30
+ }
31
+ await super.extract();
32
+ }
8
33
  }
@@ -0,0 +1,35 @@
1
+ import {DOM} from "../../src/DOM";
2
+ import "../../src/Types";
3
+ import "../../src/attributes/_imports";
4
+
5
+
6
+ describe('ScopeAttribute', () => {
7
+ it("vsn-scope should set simple values correctly", (done) => {
8
+ document.body.innerHTML = `
9
+ <div vsn-scope="{'asd':123, 'sdf': 'asd'}">
10
+ <span vsn-bind="asd"></span>
11
+ </div>
12
+ `;
13
+ const dom = new DOM(document);
14
+ dom.once('built', async () => {
15
+ const element = (await dom.exec('?(div)'))[0];
16
+ expect(element.scope.get('asd')).toBe(123);
17
+ expect(element.scope.get('sdf')).toBe('asd');
18
+ const span = (await element.exec('?>(:first-child)'))[0];
19
+ expect(span.element.innerText).toBe('123');
20
+ done();
21
+ });
22
+ });
23
+
24
+ it("vsn-scope should allow empty value to create a scope", (done) => {
25
+ document.body.innerHTML = `
26
+ <div vsn-scope></div>
27
+ `;
28
+ const dom = new DOM(document);
29
+ dom.once('built', async () => {
30
+ const element = (await dom.exec('?(div)'))[0];
31
+ expect(element.uniqueScope).toBe(true);
32
+ done();
33
+ });
34
+ });
35
+ });