tina4js 0.0.1 → 0.0.4

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/.parcelrc CHANGED
@@ -1,5 +1,5 @@
1
- {
2
- "extends": "@parcel/config-default",
3
- "resolvers": ["@parcel/resolver-glob", "..."],
4
- "reporters": ["...", "parcel-reporter-static-files-copy"]
1
+ {
2
+ "extends": "@parcel/config-default",
3
+ "resolvers": ["@parcel/resolver-glob", "..."],
4
+ "reporters": ["...", "parcel-reporter-static-files-copy"]
5
5
  }
package/bin/tina4.js ADDED
@@ -0,0 +1,103 @@
1
+ #! /usr/bin/env node
2
+ //get some params
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const args = process.argv.slice(2);
6
+ const currentDir = process.cwd();
7
+ if (args) {
8
+ switch (args[0]) {
9
+ case 'install':
10
+ let installPath = currentDir; //path.join(currentDir, '/test');
11
+ console.log(`Installing to ${installPath}...`);
12
+ install(installPath);
13
+ break;
14
+ }
15
+ }
16
+
17
+ function install(installPath) {
18
+ const indexHtmlContent = `<!DOCTYPE html>
19
+ <html>
20
+ <head>
21
+ <title>My Tina4Js App</title>
22
+ </head>
23
+ <body>
24
+ <tina4-api url="https://randomuser.me/api/" token=""></tina4-api>
25
+ <div id="root"></div>
26
+ <script type="module" src="node_modules/tina4js/tina4.ts"></script>
27
+ </body>
28
+ </html>
29
+ `;
30
+ const parcelRcContent = `{
31
+ "extends": "@parcel/config-default",
32
+ "resolvers": ["@parcel/resolver-glob", "..."],
33
+ "reporters": ["...", "parcel-reporter-static-files-copy"]
34
+ }
35
+ `;
36
+
37
+ fs.access(installPath, (err) => {
38
+ if (err) {
39
+ console.log('Creating installation path ...');
40
+ fs.mkdirSync(installPath);
41
+ }
42
+
43
+ if (!fs.existsSync(path.join(installPath, 'src'))) {
44
+ fs.mkdirSync(path.join(installPath, 'src'));
45
+ };
46
+
47
+ if (!fs.existsSync(path.join(installPath, 'src', 'routes'))) {
48
+ fs.mkdirSync(path.join(installPath, 'src', 'routes'));
49
+ };
50
+
51
+ if (!fs.existsSync(path.join(installPath, 'src', 'templates'))) {
52
+ fs.mkdirSync(path.join(installPath, 'src', 'templates'));
53
+ };
54
+
55
+
56
+ let indexHtmlFile = path.join(installPath, 'index.html');
57
+ if (!fs.existsSync(indexHtmlFile)){
58
+ fs.writeFileSync(indexHtmlFile, indexHtmlContent);
59
+ }
60
+
61
+ let parcelRcFile = path.join(installPath, '.parcelrc');
62
+ if (!fs.existsSync(parcelRcFile)){
63
+ fs.writeFileSync(parcelRcFile, parcelRcContent);
64
+ }
65
+
66
+ //add the relevant sections to the package.json
67
+ let packageFile = path.join(installPath, 'package.json');
68
+ if (fs.existsSync(packageFile)) {
69
+ console.log ('Configuring package.json ...');
70
+ fs.readFile(packageFile, 'utf8', (err, data) => {
71
+ let packageJSON = JSON.parse(data);
72
+
73
+ if (!packageJSON.name) {
74
+ packageJSON['name'] = path.basename(installPath);
75
+ }
76
+
77
+ if (!packageJSON.description) {
78
+ packageJSON['description'] = 'Another tina4js project';
79
+ }
80
+
81
+ if (!packageJSON.version) {
82
+ packageJSON['version'] = '1.0.0';
83
+ }
84
+
85
+ if (!packageJSON.staticFiles) {
86
+ packageJSON['staticFiles'] = {};
87
+ packageJSON['staticFiles']['staticPath'] = 'src/templates';
88
+ packageJSON['staticFiles']['staticOutPath'] = 'templates';
89
+ }
90
+
91
+ if (!packageJSON.scripts) {
92
+ packageJSON['scripts'] = {};
93
+ packageJSON['scripts']['start'] = 'parcel index.html';
94
+ packageJSON['scripts']['build'] = 'parcel build';
95
+ }
96
+
97
+ fs.writeFileSync(packageFile, JSON.stringify(packageJSON, null, '\t'));
98
+ });
99
+ } else {
100
+ console.log('Please make sure you have run `npm install tina4js` in this folder');
101
+ }
102
+ });
103
+ }
package/index.html CHANGED
@@ -1,11 +1,11 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Tina4 JS</title>
5
- </head>
6
- <body>
7
- <tina4-api url="https://randomuser.me/api/" token=""></tina4-api>
8
- <div id="root"></div>
9
- <script type="module" src="tina4.ts"></script>
10
- </body>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Tina4 JS</title>
5
+ </head>
6
+ <body>
7
+ <tina4-api url="https://randomuser.me/api/" token=""></tina4-api>
8
+ <div id="root"></div>
9
+ <script type="module" src="tina4.ts"></script>
10
+ </body>
11
11
  </html>
package/package.json CHANGED
@@ -1,27 +1,31 @@
1
- {
2
- "name": "tina4js",
3
- "source": "index.html",
4
- "version": "0.0.1",
5
- "description" : "This is not another framework!",
6
- "dependencies": {
7
- "fs": "^0.0.1-security",
8
- "twig": "^1.15.4"
9
- },
10
- "devDependencies": {
11
- "@parcel/resolver-glob": "^2.3.2",
12
- "@types/node": "^17.0.21",
13
- "parcel": "latest",
14
- "parcel-reporter-static-files-copy": "^1.3.4",
15
- "path-browserify": "^1.0.1",
16
- "process": "^0.11.10",
17
- "typescript": "^4.2.3"
18
- },
19
- "scripts": {
20
- "start": "parcel",
21
- "build": "parcel build"
22
- },
23
- "staticFiles": {
24
- "staticPath": "src/templates",
25
- "staticOutPath": "templates"
26
- }
27
- }
1
+ {
2
+ "name": "tina4js",
3
+ "source": "index.html",
4
+ "version": "0.0.4",
5
+ "description": "This is not another framework!",
6
+ "dependencies": {
7
+ "fs": "^0.0.1-security",
8
+ "tina4js": "^0.0.2",
9
+ "twig": "^1.15.4"
10
+ },
11
+ "devDependencies": {
12
+ "@parcel/resolver-glob": "^2.3.2",
13
+ "@types/node": "^17.0.21",
14
+ "parcel": "latest",
15
+ "parcel-reporter-static-files-copy": "^1.3.4",
16
+ "path-browserify": "^1.0.1",
17
+ "process": "^0.11.10",
18
+ "typescript": "^4.2.3"
19
+ },
20
+ "scripts": {
21
+ "start": "parcel",
22
+ "build": "parcel build"
23
+ },
24
+ "staticFiles": {
25
+ "staticPath": "src/templates",
26
+ "staticOutPath": "templates"
27
+ },
28
+ "bin": {
29
+ "tina4": "./bin/tina4.js"
30
+ }
31
+ }
package/readme.md CHANGED
@@ -1,14 +1,169 @@
1
- # Tina4js - This is not another Framework for Javascript #
2
-
3
- Right now there is not much to see, but you can start playing by doing the following
4
-
5
- ```
6
- npm install
7
- npm run start
8
- ```
9
-
10
- Components
11
-
12
- | Component | Example |
13
- |-----------|---------------------------------------------------------------|
14
- | tina4-api | ```<tina4-api url="https://randomuser.me/api/" token="" />``` |
1
+ # Tina4js - This is not another Framework for Javascript #
2
+
3
+ Right now there is not much to see, but you can start playing by following these instructions
4
+
5
+ #### Installing Parcel
6
+ ```
7
+ npm install --save-dev parcel
8
+ ```
9
+
10
+ #### Installing Tina4js
11
+ ```
12
+ npm install tina4js
13
+ ```
14
+
15
+ #### Create the src folders
16
+ Linux / MacOS
17
+ ```
18
+ mkdir src
19
+ mkdir src/routes
20
+ mkdir src/templates
21
+ ```
22
+ Windows
23
+ ```
24
+ mkdir src
25
+ mkdir src\routes
26
+ mkdir src\templates
27
+ ```
28
+
29
+ #### Create .parcelrc file
30
+ ```
31
+ echo {"extends": "@parcel/config-default","resolvers": ["@parcel/resolver-glob", "..."],"reporters": ["...", "parcel-reporter-static-files-copy"]} > .parcelrc
32
+ ```
33
+
34
+ #### Create index.html
35
+
36
+ ```html
37
+ <!DOCTYPE html>
38
+ <html>
39
+ <head>
40
+ <title>Tina4 JS</title>
41
+ </head>
42
+ <body>
43
+ <tina4-api url="https://randomuser.me/api/" token=""></tina4-api>
44
+ <div id="root"></div>
45
+ <script type="module" src="node_modules/tina4js/tina4.ts"></script>
46
+ </body>
47
+ </html>
48
+ ```
49
+
50
+ #### Add static paths & scripts
51
+ ```json
52
+ {
53
+ "devDependencies": {
54
+ },
55
+ "dependencies": {
56
+ "tina4js": "^0.0.1"
57
+ },
58
+ "staticFiles": {
59
+ "staticPath": "src/templates",
60
+ "staticOutPath": "templates"
61
+ },
62
+ "scripts": {
63
+ "start": "parcel index.html",
64
+ "build": "parcel build"
65
+ }
66
+ }
67
+ ```
68
+
69
+ #### Examples of routes
70
+
71
+ ```ts
72
+ import {Get} from "tina4js/tina4/Get";
73
+ import {Tina4} from "tina4js/tina4/Tina4";
74
+
75
+ (new Get()).add('/test/hello', function (response, request) {
76
+ let content = `<h1>Hello World Again!</h1>`;
77
+ return response(content, 200, 'text/html')
78
+ });
79
+
80
+ (new Get()).add('/test', function (response, request) {
81
+ Tina4.renderTemplate(`<h1>Hello {{name}}!</h1><form target="root" method="post"><input type="text" name="firstName" value="{{firstName}}"><button>Send</button></form>`, {
82
+ name: "Tina4",
83
+ firstName: "Tina4"
84
+ }, function (html) {
85
+ return response(html, 200, 'text/html')
86
+ }
87
+ );
88
+ });
89
+
90
+ (new Get()).add('/test/{id}', function (response, request) {
91
+ Tina4.renderTemplate(`<h1>Hello parsing params ok {{id}}!</h1>`, request, function(html) {
92
+ return response(html, 200, 'text/html');
93
+ });
94
+ });
95
+
96
+ (new Get()).add('/', function (response, request) {
97
+ Tina4.renderTemplate(`index.twig`, {test: "Hello World!", title: "Index Page"}, function(html) {
98
+ return response (html, 200, 'text/html');
99
+ });
100
+ });
101
+
102
+ ```
103
+
104
+ #### Post Routes
105
+ This is configured using the tina4-api tag in the index.html file
106
+ ```ts
107
+ import {Post} from "tina4js/tina4/Post";
108
+ import {Api} from "tina4js/tina4/Api";
109
+ import {Tina4} from "tina4js/tina4/Tina4";
110
+
111
+ (new Post()).add("/test", function (response, request) {
112
+ //Send and API request
113
+ console.log('POST WORKING', request);
114
+ Api.sendRequest('', request, 'GET', function(result) {
115
+ Tina4.renderTemplate(`contact.twig`, result, function(html){
116
+ return response(html, 200);
117
+ });
118
+ });
119
+ });
120
+ ```
121
+
122
+ ### Examples of templates
123
+
124
+ base.twig
125
+ ```twig base.twig
126
+ <div>
127
+ <nav>
128
+ <h1>Hello World Hello</h1>
129
+ <a href="#" onclick="navigate('/')">Home</a>
130
+ <a href="#" onclick="navigate('/test/hello')">Test</a>
131
+ <a href="#" onclick="navigate('/test/Hello')">Hello</a>
132
+ <a href="#" onclick="navigate('/test')">Hello</a>
133
+ </nav>
134
+ </div>
135
+ <div>
136
+ {% block content %}
137
+ Here is content
138
+ {% endblock %}
139
+ </div>
140
+ ```
141
+
142
+ index.twig
143
+ ```twig index.twig
144
+ {% extends "base.twig" %}
145
+ {% block content %}
146
+ {{ test }}
147
+ {% endblock %}
148
+ ```
149
+
150
+ contact.twig - tied to the POST route above
151
+ ```twig contact.twig
152
+ <h1>API Results</h1>
153
+ {% for result in results %}
154
+ {{result.name.first}}
155
+ <img src="{{result.picture.large}}">
156
+ {% endfor %}
157
+ ```
158
+
159
+ #### Running
160
+
161
+ ```
162
+ npm start
163
+ ```
164
+
165
+ Components
166
+
167
+ | Component | Example |
168
+ |-----------|---------------------------------------------------------------|
169
+ | tina4-api | ```<tina4-api url="https://randomuser.me/api/" token="" />``` |
package/tina4/Api.ts CHANGED
@@ -1,42 +1,42 @@
1
- import {Globals} from "./Globals";
2
- export class Api {
3
-
4
- static sendRequest (endPoint, request, method, callback) {
5
- if (endPoint === undefined) {
6
- endPoint = "";
7
- }
8
-
9
- if (request === undefined) {
10
- request = null;
11
- }
12
-
13
- if (method === undefined) {
14
- method = 'GET';
15
- }
16
-
17
- let api = Globals.get('api');
18
- if (api !== null) {
19
- endPoint = api.url + endPoint;
20
- }
21
-
22
- const xhr = new XMLHttpRequest();
23
- xhr.open(method, endPoint, true);
24
-
25
- xhr.onload = function () {
26
- let content = xhr.response;
27
- try {
28
- content = JSON.parse(content);
29
- callback(content);
30
- } catch (exception) {
31
- callback (content);
32
- }
33
- };
34
-
35
- if (method === 'POST') {
36
- xhr.send(request);
37
- } else {
38
- xhr.send(null);
39
- }
40
- }
41
-
1
+ import {Globals} from "./Globals";
2
+ export class Api {
3
+
4
+ static sendRequest (endPoint, request, method, callback) {
5
+ if (endPoint === undefined) {
6
+ endPoint = "";
7
+ }
8
+
9
+ if (request === undefined) {
10
+ request = null;
11
+ }
12
+
13
+ if (method === undefined) {
14
+ method = 'GET';
15
+ }
16
+
17
+ let api = Globals.get('api');
18
+ if (api !== null) {
19
+ endPoint = api.url + endPoint;
20
+ }
21
+
22
+ const xhr = new XMLHttpRequest();
23
+ xhr.open(method, endPoint, true);
24
+
25
+ xhr.onload = function () {
26
+ let content = xhr.response;
27
+ try {
28
+ content = JSON.parse(content);
29
+ callback(content);
30
+ } catch (exception) {
31
+ callback (content);
32
+ }
33
+ };
34
+
35
+ if (method === 'POST') {
36
+ xhr.send(request);
37
+ } else {
38
+ xhr.send(null);
39
+ }
40
+ }
41
+
42
42
  }
package/tina4/Get.ts CHANGED
@@ -1,9 +1,9 @@
1
- import {Route} from "./Route"
2
- import {Router} from "./Router";
3
-
4
- export class Get implements Route {
5
- private method : string = 'GET';
6
- add(path: string, callback): void {
7
- Router.add(this.method, path, callback)
8
- }
1
+ import {Route} from "./Route"
2
+ import {Router} from "./Router";
3
+
4
+ export class Get implements Route {
5
+ private method : string = 'GET';
6
+ add(path: string, callback): void {
7
+ Router.add(this.method, path, callback)
8
+ }
9
9
  }
package/tina4/Globals.ts CHANGED
@@ -1,32 +1,32 @@
1
- export class Globals {
2
-
3
- static initialize () {
4
- window['tina4'] = {};
5
- }
6
-
7
- static defined() {
8
- return (window['tina4'] !== undefined);
9
- }
10
-
11
- static set(name, value) {
12
- if (!this.defined()) {
13
- this.initialize();
14
- }
15
- window['tina4'][name] = value;
16
- }
17
-
18
- static append (name, value) {
19
- if (window['tina4'][name] === undefined) {
20
- window['tina4'][name] = [];
21
- }
22
- window['tina4'][name].push(value);
23
- }
24
-
25
- static get (name) {
26
- if (this.defined() && window['tina4'][name]) {
27
- return window['tina4'][name];
28
- } else {
29
- return null;
30
- }
31
- }
1
+ export class Globals {
2
+
3
+ static initialize () {
4
+ window['tina4'] = {};
5
+ }
6
+
7
+ static defined() {
8
+ return (window['tina4'] !== undefined);
9
+ }
10
+
11
+ static set(name, value) {
12
+ if (!this.defined()) {
13
+ this.initialize();
14
+ }
15
+ window['tina4'][name] = value;
16
+ }
17
+
18
+ static append (name, value) {
19
+ if (window['tina4'][name] === undefined) {
20
+ window['tina4'][name] = [];
21
+ }
22
+ window['tina4'][name].push(value);
23
+ }
24
+
25
+ static get (name) {
26
+ if (this.defined() && window['tina4'][name]) {
27
+ return window['tina4'][name];
28
+ } else {
29
+ return null;
30
+ }
31
+ }
32
32
  }
package/tina4/History.ts CHANGED
@@ -1,26 +1,26 @@
1
- export class History {
2
-
3
- static addHistory(path, target, method) {
4
- let historyInfo = JSON.parse(localStorage.getItem('history'));
5
- let pathInfo = {path: null};
6
- if (historyInfo.length > 0) {
7
- pathInfo = historyInfo[historyInfo.length - 1];
8
- }
9
- if (method === 'GET' && pathInfo.path !== path || method === 'POST') {
10
- historyInfo.push({path: path, target: target});
11
- localStorage.setItem('history', JSON.stringify(historyInfo));
12
- }
13
- }
14
-
15
- static resolveHistory() {
16
- let historyInfo = JSON.parse(localStorage.getItem('history'));
17
- historyInfo.pop();
18
- let pathInfo = {path: "/", target: null};
19
- if (historyInfo.length > 0) {
20
- pathInfo = historyInfo[historyInfo.length - 1];
21
- localStorage.setItem('history', JSON.stringify(historyInfo));
22
- }
23
- return pathInfo;
24
- }
25
-
1
+ export class History {
2
+
3
+ static addHistory(path, target, method) {
4
+ let historyInfo = JSON.parse(localStorage.getItem('history'));
5
+ let pathInfo = {path: null};
6
+ if (historyInfo.length > 0) {
7
+ pathInfo = historyInfo[historyInfo.length - 1];
8
+ }
9
+ if (method === 'GET' && pathInfo.path !== path || method === 'POST') {
10
+ historyInfo.push({path: path, target: target});
11
+ localStorage.setItem('history', JSON.stringify(historyInfo));
12
+ }
13
+ }
14
+
15
+ static resolveHistory() {
16
+ let historyInfo = JSON.parse(localStorage.getItem('history'));
17
+ historyInfo.pop();
18
+ let pathInfo = {path: "/", target: null};
19
+ if (historyInfo.length > 0) {
20
+ pathInfo = historyInfo[historyInfo.length - 1];
21
+ localStorage.setItem('history', JSON.stringify(historyInfo));
22
+ }
23
+ return pathInfo;
24
+ }
25
+
26
26
  }
package/tina4/Post.ts CHANGED
@@ -1,10 +1,10 @@
1
- import {Route} from "./Route"
2
- import {Router} from "./Router";
3
-
4
- export class Post implements Route {
5
- static;
6
- private method : string = 'POST';
7
- add(path: string, callback): void {
8
- Router.add(this.method, path, callback)
9
- }
1
+ import {Route} from "./Route"
2
+ import {Router} from "./Router";
3
+
4
+ export class Post implements Route {
5
+ static;
6
+ private method : string = 'POST';
7
+ add(path: string, callback): void {
8
+ Router.add(this.method, path, callback)
9
+ }
10
10
  }
package/tina4/Route.ts CHANGED
@@ -1,3 +1,3 @@
1
- export interface Route {
2
- add(path: string, callback):void;
1
+ export interface Route {
2
+ add(path: string, callback):void;
3
3
  }
package/tina4/Router.ts CHANGED
@@ -1,163 +1,163 @@
1
- import {Globals} from "./Globals";
2
- import {Tina4} from "./Tina4";
3
-
4
- export class Router {
5
-
6
- private readonly url: string;
7
- private readonly target: string;
8
- private readonly method: string;
9
- private readonly data;
10
- private matchesPath;
11
- private matchesUrl;
12
- private params;
13
- private matched;
14
-
15
- constructor(url, target, method, data=null) {
16
- //console.log('Constructing', url, target, method, data);
17
- if (method === undefined) method = 'GET';
18
- this.url = url;
19
- this.target = target;
20
- this.method = method;
21
- this.data = data;
22
- }
23
-
24
- static add(method, path, callback) {
25
- Tina4.initialize();
26
- //console.log('Adding Route', method, path);
27
- if (Globals.defined()) {
28
- Globals.append('routes', {method: method, path: path, callback: callback});
29
- }
30
- }
31
-
32
- static response(content, httpCode, contentType) {
33
- console.log('Response', content, httpCode, contentType);
34
-
35
- //manipulate content based on the contentType
36
- if ( typeof content === 'object' &&
37
- !Array.isArray(content) &&
38
- content !== null
39
- ) {
40
- content = JSON.stringify(content);
41
- }
42
-
43
- return content;
44
- }
45
-
46
- //https://stackoverflow.com/questions/831030/how-to-get-get-request-parameters-in-javascript
47
- getRequestParams() {
48
- let s1 = location.search.substring(1, location.search.length).split('&'),
49
- r = {}, s2, i;
50
- for (i = 0; i < s1.length; i += 1) {
51
- s2 = s1[i].split('=');
52
- r[decodeURIComponent(s2[0])] = decodeURIComponent(s2[1]);
53
- }
54
-
55
- if (JSON.stringify(r) == '{"":"undefined"}') return {};
56
- return r;
57
- };
58
-
59
- cleanUrl(url) {
60
- const regex = /(.*)\/\/(.*)\//g;
61
- url = url.replace(regex, '/').replace('#','');
62
- return url;
63
- }
64
-
65
- match (url:string, path:string, method:string): boolean {
66
- if (this.method !== method) return false;
67
- url = this.cleanUrl(url);
68
- //console.log('Matching', url, path, method);
69
- const urlExpression = /(.*)\/(.*)|{(.*)}/g;
70
- const pathExpression = /(.*)\/(.*)|{(.*)}/g;
71
-
72
- if (url === path) {
73
- return true;
74
- } else {
75
- this.matchesUrl = urlExpression.exec (url);
76
- this.matchesPath = pathExpression.exec (path);
77
- if (this.matchesUrl.length === this.matchesPath.length) {
78
- this.matched = true;
79
- this.matchesUrl.every(function (urlPath, index) {
80
- if (index !== 0 && urlPath !== undefined) {
81
- //console.log('Matching', urlPath, this.matchesPath[index]);
82
- if (urlPath !== this.matchesPath[index] && this.matchesPath[index][0] !== '{') {
83
- //console.log('Not matching', url, path);
84
- this.matched = false;
85
- return false;
86
- } else if (this.matchesPath[index][0] === '{') {
87
- this.params[this.matchesPath[index].replace('{', '').replace('}', '')] = urlPath;
88
- this.matched = true;
89
- }
90
- }
91
- return true;
92
- }, this);
93
- if (this.matched) return true;
94
- } else {
95
- return false;
96
- }
97
- }
98
- }
99
-
100
- parse(url: string, target: string, callback) {
101
- //console.log (window['tina4']['routes']);
102
- let routes = Globals.get('routes');
103
- let rendered = false;
104
- routes.every(function(route){
105
- if (this.match(url, route.path, route.method )) {
106
- if (route.method === 'GET') {
107
- history.pushState({}, '', url);
108
- }
109
- route.callback( function(content, httpCode, contentType) {
110
- callback ( target, Router.response(content, httpCode, contentType) );
111
- }, this.params );
112
- rendered = true;
113
- }
114
- return true;
115
- }.bind(this));
116
-
117
- if (!rendered) {
118
- //See if we can find a twig file
119
- Tina4.renderTemplate(`${url}.twig`, {}, function (html) {
120
- callback(target, Router.response(html, 200, 'text/html'));
121
- });
122
- }
123
- }
124
-
125
- submitHandler(event) {
126
- if (event.preventDefault) event.preventDefault();
127
- let form = event.target;
128
- //console.log ('Form', form.action, window.location.pathname, form);
129
- if (form.action === undefined) form.action = window.location.pathname;
130
-
131
- // @ts-ignore
132
- window.navigate(form.action, form.getAttribute("target") , 'POST', form);
133
- }
134
-
135
- run() {
136
- // @ts-ignore
137
- window.submitHandler = this.submitHandler;
138
- this.params = this.getRequestParams();
139
- this.params.data = this.data;
140
- this.parse(this.url, this.target, function (target, content) {
141
- //console.log ('Target', target, content);
142
- if (document.getElementById(target) !== null) {
143
- document.getElementById(target).innerHTML = content;
144
- //Attach the form submit handler
145
- let forms = Array.prototype.slice.call(document.getElementsByTagName('form'));
146
- forms.forEach(function (form) {
147
- //console.log('Found form', form.method);
148
- if (form.attachEvent) {
149
- // @ts-ignore
150
- form.attachEvent("submit", window.submitHandler);
151
- } else {
152
- // @ts-ignore
153
- form.addEventListener("submit", window.submitHandler);
154
- }
155
- });
156
- } else {
157
- console.log('Cannot find route')
158
- }
159
- });
160
- }
161
- }
162
-
163
-
1
+ import {Globals} from "./Globals";
2
+ import {Tina4} from "./Tina4";
3
+
4
+ export class Router {
5
+
6
+ private readonly url: string;
7
+ private readonly target: string;
8
+ private readonly method: string;
9
+ private readonly data;
10
+ private matchesPath;
11
+ private matchesUrl;
12
+ private params;
13
+ private matched;
14
+
15
+ constructor(url, target, method, data=null) {
16
+ //console.log('Constructing', url, target, method, data);
17
+ if (method === undefined) method = 'GET';
18
+ this.url = url;
19
+ this.target = target;
20
+ this.method = method;
21
+ this.data = data;
22
+ }
23
+
24
+ static add(method, path, callback) {
25
+ Tina4.initialize();
26
+ //console.log('Adding Route', method, path);
27
+ if (Globals.defined()) {
28
+ Globals.append('routes', {method: method, path: path, callback: callback});
29
+ }
30
+ }
31
+
32
+ static response(content, httpCode, contentType) {
33
+ console.log('Response', content, httpCode, contentType);
34
+
35
+ //manipulate content based on the contentType
36
+ if ( typeof content === 'object' &&
37
+ !Array.isArray(content) &&
38
+ content !== null
39
+ ) {
40
+ content = JSON.stringify(content);
41
+ }
42
+
43
+ return content;
44
+ }
45
+
46
+ //https://stackoverflow.com/questions/831030/how-to-get-get-request-parameters-in-javascript
47
+ getRequestParams() {
48
+ let s1 = location.search.substring(1, location.search.length).split('&'),
49
+ r = {}, s2, i;
50
+ for (i = 0; i < s1.length; i += 1) {
51
+ s2 = s1[i].split('=');
52
+ r[decodeURIComponent(s2[0])] = decodeURIComponent(s2[1]);
53
+ }
54
+
55
+ if (JSON.stringify(r) == '{"":"undefined"}') return {};
56
+ return r;
57
+ };
58
+
59
+ cleanUrl(url) {
60
+ const regex = /(.*)\/\/(.*)\//g;
61
+ url = url.replace(regex, '/').replace('#','');
62
+ return url;
63
+ }
64
+
65
+ match (url:string, path:string, method:string): boolean {
66
+ if (this.method !== method) return false;
67
+ url = this.cleanUrl(url);
68
+ //console.log('Matching', url, path, method);
69
+ const urlExpression = /(.*)\/(.*)|{(.*)}/g;
70
+ const pathExpression = /(.*)\/(.*)|{(.*)}/g;
71
+
72
+ if (url === path) {
73
+ return true;
74
+ } else {
75
+ this.matchesUrl = urlExpression.exec (url);
76
+ this.matchesPath = pathExpression.exec (path);
77
+ if (this.matchesUrl.length === this.matchesPath.length) {
78
+ this.matched = true;
79
+ this.matchesUrl.every(function (urlPath, index) {
80
+ if (index !== 0 && urlPath !== undefined) {
81
+ //console.log('Matching', urlPath, this.matchesPath[index]);
82
+ if (urlPath !== this.matchesPath[index] && this.matchesPath[index][0] !== '{') {
83
+ //console.log('Not matching', url, path);
84
+ this.matched = false;
85
+ return false;
86
+ } else if (this.matchesPath[index][0] === '{') {
87
+ this.params[this.matchesPath[index].replace('{', '').replace('}', '')] = urlPath;
88
+ this.matched = true;
89
+ }
90
+ }
91
+ return true;
92
+ }, this);
93
+ if (this.matched) return true;
94
+ } else {
95
+ return false;
96
+ }
97
+ }
98
+ }
99
+
100
+ parse(url: string, target: string, callback) {
101
+ //console.log (window['tina4']['routes']);
102
+ let routes = Globals.get('routes');
103
+ let rendered = false;
104
+ routes.every(function(route){
105
+ if (this.match(url, route.path, route.method )) {
106
+ if (route.method === 'GET') {
107
+ history.pushState({}, '', url);
108
+ }
109
+ route.callback( function(content, httpCode, contentType) {
110
+ callback ( target, Router.response(content, httpCode, contentType) );
111
+ }, this.params );
112
+ rendered = true;
113
+ }
114
+ return true;
115
+ }.bind(this));
116
+
117
+ if (!rendered) {
118
+ //See if we can find a twig file
119
+ Tina4.renderTemplate(`${url}.twig`, {}, function (html) {
120
+ callback(target, Router.response(html, 200, 'text/html'));
121
+ });
122
+ }
123
+ }
124
+
125
+ submitHandler(event) {
126
+ if (event.preventDefault) event.preventDefault();
127
+ let form = event.target;
128
+ //console.log ('Form', form.action, window.location.pathname, form);
129
+ if (form.action === undefined) form.action = window.location.pathname;
130
+
131
+ // @ts-ignore
132
+ window.navigate(form.action, form.getAttribute("target") , 'POST', form);
133
+ }
134
+
135
+ run() {
136
+ // @ts-ignore
137
+ window.submitHandler = this.submitHandler;
138
+ this.params = this.getRequestParams();
139
+ this.params.data = this.data;
140
+ this.parse(this.url, this.target, function (target, content) {
141
+ //console.log ('Target', target, content);
142
+ if (document.getElementById(target) !== null) {
143
+ document.getElementById(target).innerHTML = content;
144
+ //Attach the form submit handler
145
+ let forms = Array.prototype.slice.call(document.getElementsByTagName('form'));
146
+ forms.forEach(function (form) {
147
+ //console.log('Found form', form.method);
148
+ if (form.attachEvent) {
149
+ // @ts-ignore
150
+ form.attachEvent("submit", window.submitHandler);
151
+ } else {
152
+ // @ts-ignore
153
+ form.addEventListener("submit", window.submitHandler);
154
+ }
155
+ });
156
+ } else {
157
+ console.log('Cannot find route')
158
+ }
159
+ });
160
+ }
161
+ }
162
+
163
+
package/tina4/Tina4.ts CHANGED
@@ -1,95 +1,95 @@
1
- import {Globals} from "./Globals"
2
- import {Router} from "./Router";
3
- import {History} from "./History";
4
- import Twig from 'twig';
5
- import {Tina4Config} from "./components/Tina4Config";
6
- import {Tina4Api} from "./components/Tina4Api";
7
-
8
- export class Tina4 {
9
- constructor(config = null) {
10
- if (config === undefined || config === null) {
11
- if (Globals.defined() && Globals.get('config')) {
12
- config = Globals.get('config');
13
- } else {
14
- config = {defaultTarget: 'root'};
15
- }
16
- }
17
- console.log('Config found', config);
18
- Tina4.resolveRoutes(window.location.pathname, config.defaultTarget);
19
- }
20
-
21
- static initialize(config = null) {
22
- if (!Globals.defined()) {
23
- console.log('Initialize Tina4');
24
- Globals.initialize();
25
- Globals.set('routes', []);
26
- Globals.set('twig', Twig);
27
- localStorage.setItem('history', JSON.stringify([]));
28
- Tina4.registerComponents();
29
- }
30
-
31
- if (config !== null) {
32
- Globals.set('config', config);
33
- } else {
34
- Globals.set('config', {defaultTarget: 'root'});
35
- }
36
-
37
- //back navigation in the browser
38
- window.onpopstate=function(e){
39
- if (e.state) {
40
- let pathInfo = History.resolveHistory ();
41
- Tina4.resolveRoutes(pathInfo.path, pathInfo.target, 'GET', {});
42
- }
43
- }
44
-
45
- //add the navigate handler
46
- // @ts-ignore
47
- window.navigate = function (path, target = 'root', method: string = 'GET', data = null) {
48
- if (Globals.get('config').defaultTarget !== null) {
49
- target = Globals.get('config').defaultTarget;
50
- }
51
-
52
- Tina4.resolveRoutes(path, target, method, data);
53
- };
54
- }
55
-
56
- static registerComponents() {
57
- console.log('Register components');
58
- customElements.define('tina4-config', Tina4Config);
59
- customElements.define('tina4-api', Tina4Api);
60
- }
61
-
62
- static resolveRoutes(path, target, method: string = 'GET', data = null) {
63
- History.addHistory (path, target, method);
64
- return new Router(path, target, method, data).run();
65
- }
66
-
67
- static getFileExtension(filename) {
68
- let split = filename.trim().split('.');
69
- return split[split.length - 1];
70
- }
71
-
72
- static renderTemplate(content, params, callback) {
73
- if (this.getFileExtension(content) == 'twig') {
74
- try {
75
- Twig.twig(
76
- {
77
- id: content,
78
- href: `/templates/${content}`,
79
- async:true,
80
- load: (template) => {
81
- console.log(`Template loaded: `, template, params);
82
- callback(template.render(params));
83
- }
84
- });
85
- }
86
- catch(exception) {
87
- callback( Twig.twig({ref: content}).render(params));
88
- }
89
- } else {
90
- let template = Twig.twig({data: content});
91
- callback( template.render(params));
92
- }
93
- return false;
94
- }
1
+ import {Globals} from "./Globals"
2
+ import {Router} from "./Router";
3
+ import {History} from "./History";
4
+ import Twig from 'twig';
5
+ import {Tina4Config} from "./components/Tina4Config";
6
+ import {Tina4Api} from "./components/Tina4Api";
7
+
8
+ export class Tina4 {
9
+ constructor(config = null) {
10
+ if (config === undefined || config === null) {
11
+ if (Globals.defined() && Globals.get('config')) {
12
+ config = Globals.get('config');
13
+ } else {
14
+ config = {defaultTarget: 'root'};
15
+ }
16
+ }
17
+ console.log('Config found', config);
18
+ Tina4.resolveRoutes(window.location.pathname, config.defaultTarget);
19
+ }
20
+
21
+ static initialize(config = null) {
22
+ if (!Globals.defined()) {
23
+ console.log('Initialize Tina4');
24
+ Globals.initialize();
25
+ Globals.set('routes', []);
26
+ Globals.set('twig', Twig);
27
+ localStorage.setItem('history', JSON.stringify([]));
28
+ Tina4.registerComponents();
29
+ }
30
+
31
+ if (config !== null) {
32
+ Globals.set('config', config);
33
+ } else {
34
+ Globals.set('config', {defaultTarget: 'root'});
35
+ }
36
+
37
+ //back navigation in the browser
38
+ window.onpopstate=function(e){
39
+ if (e.state) {
40
+ let pathInfo = History.resolveHistory ();
41
+ Tina4.resolveRoutes(pathInfo.path, pathInfo.target, 'GET', {});
42
+ }
43
+ }
44
+
45
+ //add the navigate handler
46
+ // @ts-ignore
47
+ window.navigate = function (path, target = 'root', method: string = 'GET', data = null) {
48
+ if (Globals.get('config').defaultTarget !== null) {
49
+ target = Globals.get('config').defaultTarget;
50
+ }
51
+
52
+ Tina4.resolveRoutes(path, target, method, data);
53
+ };
54
+ }
55
+
56
+ static registerComponents() {
57
+ console.log('Register components');
58
+ customElements.define('tina4-config', Tina4Config);
59
+ customElements.define('tina4-api', Tina4Api);
60
+ }
61
+
62
+ static resolveRoutes(path, target, method: string = 'GET', data = null) {
63
+ History.addHistory (path, target, method);
64
+ return new Router(path, target, method, data).run();
65
+ }
66
+
67
+ static getFileExtension(filename) {
68
+ let split = filename.trim().split('.');
69
+ return split[split.length - 1];
70
+ }
71
+
72
+ static renderTemplate(content, params, callback) {
73
+ if (this.getFileExtension(content) == 'twig') {
74
+ try {
75
+ Twig.twig(
76
+ {
77
+ id: content,
78
+ href: `/templates/${content}`,
79
+ async:true,
80
+ load: (template) => {
81
+ console.log(`Template loaded: `, template, params);
82
+ callback(template.render(params));
83
+ }
84
+ });
85
+ }
86
+ catch(exception) {
87
+ callback( Twig.twig({ref: content}).render(params));
88
+ }
89
+ } else {
90
+ let template = Twig.twig({data: content});
91
+ callback( template.render(params));
92
+ }
93
+ return false;
94
+ }
95
95
  }
@@ -1,12 +1,12 @@
1
- import {Globals} from "../Globals";
2
-
3
- export class Tina4Api extends HTMLElement {
4
- constructor() {
5
- // Always call super first in constructor
6
- super();
7
- let api = {};
8
- api['url'] = this.getAttribute('url');
9
- api['token'] = this.getAttribute('token');
10
- Globals.set('api', api);
11
- }
12
- }
1
+ import {Globals} from "../Globals";
2
+
3
+ export class Tina4Api extends HTMLElement {
4
+ constructor() {
5
+ // Always call super first in constructor
6
+ super();
7
+ let api = {};
8
+ api['url'] = this.getAttribute('url');
9
+ api['token'] = this.getAttribute('token');
10
+ Globals.set('api', api);
11
+ }
12
+ }
@@ -1,9 +1,9 @@
1
- export class Tina4Config extends HTMLElement {
2
- constructor() {
3
- // Always call super first in constructor
4
- super();
5
-
6
- // write element functionality in here
7
- console.log ('Here!', this.getAttribute('name'));
8
- }
9
- }
1
+ export class Tina4Config extends HTMLElement {
2
+ constructor() {
3
+ // Always call super first in constructor
4
+ super();
5
+
6
+ // write element functionality in here
7
+ console.log ('Here!', this.getAttribute('name'));
8
+ }
9
+ }
package/tina4.ts CHANGED
@@ -1,4 +1,5 @@
1
- import {Tina4} from "./tina4/Tina4";
2
- Tina4.initialize({defaultTarget: 'root'});
3
- import "./src/routes/**";
4
- let tina4 = new Tina4();
1
+ import {Tina4} from "./tina4/Tina4";
2
+ Tina4.initialize({defaultTarget: 'root'});
3
+ import "./src/routes/**";
4
+ import "../../src/routes/**";
5
+ let tina4 = new Tina4();
@@ -1,35 +0,0 @@
1
- import {Tina4} from "../../tina4/Tina4";
2
- import {Get} from "../../tina4/Get";
3
- import {Post} from "../../tina4/Post";
4
- import {Api} from "../../tina4/Api";
5
-
6
- (new Get()).add('/test/hello', function (response, request) {
7
- let content = `<h1>Hello World Again!</h1>`;
8
- response(content, 200, 'text/html')
9
- });
10
-
11
- (new Get()).add('/test', function (response, request) {
12
- Tina4.renderTemplate(`<h1>Hello {{name}}!</h1><form target="root" method="post"><input type="text" name="firstName" value="{{firstName}}"><button>Send</button></form>`, {
13
- name: "Andre",
14
- firstName: "Andre"
15
- }, function (html) {
16
- console.log('OOO');
17
- response(html, 200, 'text/html')
18
- }
19
- );
20
- });
21
-
22
- (new Get()).add('/test/{id}', function (response, request) {
23
- Tina4.renderTemplate(`<h1>Hello parsing params ok {{id}}!</h1>`, request, function(html) {
24
- response(html, 200, 'text/html');
25
- });
26
- });
27
-
28
-
29
-
30
-
31
- (new Get()).add('/', function (response, request) {
32
- Tina4.renderTemplate(`index.twig`, {test: "Hello World!", title: "Index Page"}, function(html) {
33
- response (html, 200, 'text/html');
34
- });
35
- });
@@ -1,13 +0,0 @@
1
- import {Post} from "../../tina4/Post";
2
- import {Api} from "../../tina4/Api";
3
- import {Tina4} from "../../tina4/Tina4";
4
-
5
- (new Post()).add("/test", function (response, request) {
6
- //Send and API request
7
- console.log('POST WORKING', request);
8
- Api.sendRequest('', request, 'GET', function(result) {
9
- Tina4.renderTemplate(`contact.twig`, result, function(html){
10
- response(html, 200);
11
- });
12
- });
13
- });
@@ -1,14 +0,0 @@
1
- <div>
2
- <nav>
3
- <h1>Hello World Hello</h1>
4
- <a href="#" onclick="navigate('/')">Home</a>
5
- <a href="#" onclick="navigate('/test/hello')">Test</a>
6
- <a href="#" onclick="navigate('/test/Hello')">Hello</a>
7
- <a href="#" onclick="navigate('/test')">Hello</a>
8
- </nav>
9
- </div>
10
- <div>
11
- {% block content %}
12
- Here is content
13
- {% endblock %}
14
- </div>
@@ -1,5 +0,0 @@
1
- <h1>Hello</h1>
2
- {% for result in results %}
3
- {{result.name.first}}
4
- <img src="{{result.picture.large}}">
5
- {% endfor %}
@@ -1,4 +0,0 @@
1
- {% extends "base.twig" %}
2
- {% block content %}
3
- {{ test }}
4
- {% endblock %}