@blaasvaer/frmwrk 0.1.7 → 0.1.8
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/.vscode/settings.json +7 -1
- package/connections.js +12 -7
- package/controllers.js +2 -3
- package/handle-request.js +22 -40
- package/index.js +20 -30
- package/models.js +1 -1
- package/package.json +1 -1
- package/router.js +97 -5
- package/views.js +8 -3
package/.vscode/settings.json
CHANGED
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
"titleBar.activeBackground": "#215732",
|
|
14
14
|
"titleBar.activeForeground": "#e7e7e7",
|
|
15
15
|
"titleBar.inactiveBackground": "#21573299",
|
|
16
|
-
"titleBar.inactiveForeground": "#e7e7e799"
|
|
16
|
+
"titleBar.inactiveForeground": "#e7e7e799",
|
|
17
|
+
"editorGroup.border": "#2f7c47",
|
|
18
|
+
"panel.border": "#2f7c47",
|
|
19
|
+
"sash.hoverBorder": "#2f7c47",
|
|
20
|
+
"sideBar.border": "#2f7c47",
|
|
21
|
+
"statusBarItem.remoteBackground": "#215732",
|
|
22
|
+
"statusBarItem.remoteForeground": "#e7e7e7"
|
|
17
23
|
},
|
|
18
24
|
"peacock.color": "#215732"
|
|
19
25
|
}
|
package/connections.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
1
|
const utils = require('./utils');
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -23,17 +22,23 @@ function installconnections ( config ) {
|
|
|
23
22
|
|
|
24
23
|
let connection = require( connections_dir + file );
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
if ( connection ) {
|
|
26
|
+
// FW.connections[ path.parse(file).name ] = connection;
|
|
27
|
+
FW.connections[ file.split('.')[0] ] = connection;
|
|
28
|
+
|
|
29
|
+
// Check for config connection type
|
|
30
|
+
if ( config.connection && FW.connections[ config.connection ] ) {
|
|
31
|
+
FW.database = FW.connections[ config.connection ];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resolve( file );
|
|
35
|
+
} else {
|
|
36
|
+
reject( "Loading of connection: " + file + " failed!" );
|
|
31
37
|
}
|
|
32
38
|
});
|
|
33
39
|
|
|
34
40
|
connection_files.push( promise );
|
|
35
41
|
});
|
|
36
|
-
// console.log("connection file require()", FW.connections);
|
|
37
42
|
|
|
38
43
|
return Promise.all( connection_files );
|
|
39
44
|
});
|
package/controllers.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
const utils = require('
|
|
1
|
+
const utils = require('@blaasvaer/frmwrk/utils');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Install Controllers
|
|
5
5
|
*/
|
|
6
6
|
function installControllers ( config ) {
|
|
7
|
-
// console.log("Installing controllers …", config);
|
|
8
7
|
let controllers_dir = config.root + '/controllers/';
|
|
9
8
|
|
|
10
9
|
return utils.readdirAsync( controllers_dir )
|
|
@@ -38,7 +37,7 @@ function installControllers ( config ) {
|
|
|
38
37
|
|
|
39
38
|
controller_files.push( promise );
|
|
40
39
|
});
|
|
41
|
-
|
|
40
|
+
|
|
42
41
|
return Promise.all( controller_files );
|
|
43
42
|
});
|
|
44
43
|
}
|
package/handle-request.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const statics = require('serve-handler');
|
|
6
|
+
const Url = require('url');
|
|
7
|
+
const { findRoute, Router } = require('./router');
|
|
6
8
|
|
|
7
9
|
const content_types = {
|
|
8
10
|
"text" : 'text/plain; charset=utf-8',
|
|
@@ -17,14 +19,8 @@ const content_types = {
|
|
|
17
19
|
* @return {Object} Return the response
|
|
18
20
|
*/
|
|
19
21
|
async function handleRequest( req, res ) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* @type {[type]}
|
|
23
|
-
*/
|
|
24
|
-
const SOME_CONTROLLER_EXISTS = true;
|
|
25
|
-
const method = req.method;
|
|
26
|
-
const url = FW.utils.removeTrailingSlashes( req.url );
|
|
27
|
-
const query = url.split('/').splice(3); // Get url parts as parameters
|
|
22
|
+
// console.log("Cookies",req.headers);
|
|
23
|
+
const request_url = new URL( req.url, `http://${req.headers.host}`);
|
|
28
24
|
|
|
29
25
|
/**
|
|
30
26
|
* Set default status and header
|
|
@@ -34,14 +30,11 @@ async function handleRequest( req, res ) {
|
|
|
34
30
|
let content_type = 'html';
|
|
35
31
|
|
|
36
32
|
// Prevent errors from missing favicon
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
* TODO: Set theme dynamically
|
|
40
|
-
*/
|
|
33
|
+
if (request_url.pathname === '/favicon.ico') {
|
|
34
|
+
// TODO: Set theme dynamically
|
|
41
35
|
var favicon = path.join('themes/default', 'favicon.ico');
|
|
42
36
|
res.statusCode = 200;
|
|
43
37
|
res.setHeader('Content-Type', 'image/x-icon');
|
|
44
|
-
// const icon = fs.createReadStream( favicon );
|
|
45
38
|
|
|
46
39
|
if ( fs.existsSync( favicon ) ) {
|
|
47
40
|
fs.createReadStream( favicon ).pipe( res );
|
|
@@ -54,9 +47,9 @@ async function handleRequest( req, res ) {
|
|
|
54
47
|
/**
|
|
55
48
|
* Find route in Router based on url
|
|
56
49
|
*/
|
|
57
|
-
const route = global.routes.find(( obj ) => obj.route ===
|
|
58
|
-
const
|
|
59
|
-
|
|
50
|
+
// const route = global.routes.find( ( obj ) => obj.route === FW.utils.removeTrailingSlashes( request_url.pathname ) );
|
|
51
|
+
const route = findRoute( request_url.pathname );
|
|
52
|
+
// console.log("route", route);
|
|
60
53
|
/**
|
|
61
54
|
* Check for complete route
|
|
62
55
|
* @param {[type]} route [description]
|
|
@@ -66,26 +59,7 @@ async function handleRequest( req, res ) {
|
|
|
66
59
|
/**
|
|
67
60
|
* Create new controller from route
|
|
68
61
|
*/
|
|
69
|
-
const controller = new Controller( route, req, res
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* TODO
|
|
73
|
-
* Figure out how to receive data and handle it properly (in a general and robust way) in routing
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Prepare body
|
|
78
|
-
* @type {String}
|
|
79
|
-
*/
|
|
80
|
-
let body = '';
|
|
81
|
-
|
|
82
|
-
req.on('data', ( chunk ) => {
|
|
83
|
-
body += chunk;
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
req.on('end', () => {
|
|
87
|
-
controller.addBody( body );
|
|
88
|
-
})
|
|
62
|
+
const controller = new Controller( route, req, res );
|
|
89
63
|
|
|
90
64
|
let response_output = 'Nothing here …';
|
|
91
65
|
|
|
@@ -93,13 +67,13 @@ async function handleRequest( req, res ) {
|
|
|
93
67
|
/**
|
|
94
68
|
* If the route has no parameters, then just run the route method and serve whatever it may …
|
|
95
69
|
*/
|
|
96
|
-
response_output = await controller.route.action();
|
|
70
|
+
response_output = await controller.route.action( route );
|
|
97
71
|
} else {
|
|
98
72
|
/**
|
|
99
73
|
* Authorization
|
|
100
74
|
*/
|
|
101
75
|
if ( Authorize( controller.route ) ) {
|
|
102
|
-
response_output = await controller.route.action();
|
|
76
|
+
response_output = await controller.route.action( route );
|
|
103
77
|
} else {
|
|
104
78
|
/**
|
|
105
79
|
* Redirect the user to login if auth fails
|
|
@@ -121,8 +95,16 @@ async function handleRequest( req, res ) {
|
|
|
121
95
|
|
|
122
96
|
res.statusCode = status_code;
|
|
123
97
|
res.setHeader( 'Content-Type', content_types[content_type] );
|
|
98
|
+
|
|
99
|
+
// Cookies
|
|
100
|
+
res.setHeader('Set-Cookie','uuid=1234-1324-1234-1234-1234; Max-Age=3000; SameSite=lax; Secure');
|
|
101
|
+
// Set a same-site cookie for first-party contexts
|
|
102
|
+
// res.cookie('cookie1', 'value1', { sameSite: 'lax' });
|
|
103
|
+
// Set a cross-site cookie for third-party contexts
|
|
104
|
+
// res.cookie('cookie2', 'value2', { sameSite: 'none', secure: true });
|
|
105
|
+
|
|
124
106
|
res.end( response_output );
|
|
125
|
-
} else if (
|
|
107
|
+
} else if ( request_url.pathname.split('/')[1] == 'themes' ) {
|
|
126
108
|
/**
|
|
127
109
|
* Serve static files from public directory
|
|
128
110
|
*/
|
|
@@ -136,7 +118,7 @@ async function handleRequest( req, res ) {
|
|
|
136
118
|
} else {
|
|
137
119
|
res.statusCode = 404;
|
|
138
120
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8' );
|
|
139
|
-
res.end("404 – Page not found: " +
|
|
121
|
+
res.end("404 – Page not found: " + request_url + ".\n\nDo you have a controller with an action for that route?");
|
|
140
122
|
}
|
|
141
123
|
}
|
|
142
124
|
|
package/index.js
CHANGED
|
@@ -10,19 +10,17 @@
|
|
|
10
10
|
* Native modules
|
|
11
11
|
*/
|
|
12
12
|
const http = require('http');
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Custom modules
|
|
16
15
|
*/
|
|
17
16
|
const handleRequest = require('./handle-request');
|
|
18
|
-
const router = require('./router');
|
|
19
17
|
const Utils = require('./utils');
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
20
|
* Define variables
|
|
23
21
|
*/
|
|
24
22
|
let hostname,
|
|
25
|
-
|
|
23
|
+
server;
|
|
26
24
|
|
|
27
25
|
/**
|
|
28
26
|
* If port number is passed in as first (custom) parameter, set port
|
|
@@ -40,20 +38,21 @@ if ( process.env.NODE_ENV !== 'production') {
|
|
|
40
38
|
* @param {object} config The configuration object
|
|
41
39
|
* @return {Node} Node
|
|
42
40
|
*/
|
|
43
|
-
|
|
41
|
+
FW = function ( config ) {
|
|
42
|
+
let _this = this;
|
|
43
|
+
|
|
44
44
|
hostname = config.hostname ? config.hostname : '127.0.0.1';
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
controllers = {};
|
|
47
|
+
models = {};
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Create and start the server
|
|
51
51
|
* @return {function} Server instance
|
|
52
52
|
*/
|
|
53
|
-
|
|
53
|
+
http.createServer( handleRequest ).listen(port, hostname, () => {
|
|
54
54
|
console.log(`Server running at http://${hostname}:${port}`);
|
|
55
55
|
});
|
|
56
|
-
// console.log("This.server:", this.server);
|
|
57
56
|
|
|
58
57
|
/**
|
|
59
58
|
* Set the Controller
|
|
@@ -61,11 +60,11 @@ if ( process.env.NODE_ENV !== 'production') {
|
|
|
61
60
|
* @param {object} req The incomming request object
|
|
62
61
|
* @param {object} res The response object
|
|
63
62
|
*/
|
|
64
|
-
Controller = function Controller ( route, req, res
|
|
63
|
+
Controller = function Controller ( route, req, res ) {
|
|
64
|
+
// console.log("Controller in index:\n", _this);
|
|
65
65
|
this.route = route;
|
|
66
66
|
this.req = req;
|
|
67
67
|
this.res = res;
|
|
68
|
-
this.query = query;
|
|
69
68
|
|
|
70
69
|
/**
|
|
71
70
|
* Check for authorization parameters.
|
|
@@ -75,32 +74,31 @@ if ( process.env.NODE_ENV !== 'production') {
|
|
|
75
74
|
console.log("This route should be authorized!");
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
return this;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
Controller.prototype.addBody = function addBody ( body ) {
|
|
83
|
-
this.body = body;
|
|
84
|
-
console.log("Controller.addBody:", this.body);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
81
|
/**
|
|
88
|
-
* Authorize user
|
|
82
|
+
* TODO: Authorize user
|
|
89
83
|
*/
|
|
90
84
|
Authorize = function Authorize ( credentials ) {
|
|
91
|
-
// console.log("Authorize - credentials:", credentials
|
|
85
|
+
// console.log("Authorize - check credentials:", credentials);
|
|
92
86
|
return true;
|
|
93
87
|
}
|
|
94
88
|
|
|
95
89
|
/**
|
|
96
90
|
* Install framework components and start the server
|
|
97
91
|
*/
|
|
98
|
-
Install( config )
|
|
92
|
+
Install( config )
|
|
93
|
+
.then(( result ) => {
|
|
99
94
|
/**
|
|
100
95
|
* Run post install processes here …
|
|
101
96
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
// console.log("Install result:", routes);
|
|
98
|
+
})
|
|
99
|
+
.catch(function( err ) {
|
|
100
|
+
console.log("Install Error:", err);
|
|
101
|
+
});;
|
|
104
102
|
};
|
|
105
103
|
|
|
106
104
|
/**
|
|
@@ -125,15 +123,7 @@ global.Install = function Install ( config ) {
|
|
|
125
123
|
// require('./users')( config )
|
|
126
124
|
];
|
|
127
125
|
|
|
128
|
-
return Promise.all( install_processes )
|
|
129
|
-
.then(function( result ) {
|
|
130
|
-
console.log("Install result", result);
|
|
131
|
-
// console.log("Routes", global.routes );
|
|
132
|
-
// console.log("User:", global.users );
|
|
133
|
-
})
|
|
134
|
-
.catch(function( err ) {
|
|
135
|
-
console.log("Install Error:", err);
|
|
136
|
-
});
|
|
126
|
+
return Promise.all( install_processes );
|
|
137
127
|
}
|
|
138
128
|
|
|
139
129
|
FW.utils = Utils;
|
package/models.js
CHANGED
package/package.json
CHANGED
package/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This is the router for the
|
|
2
|
+
* This is the router for the fw framework.
|
|
3
3
|
*
|
|
4
4
|
* @author Sam Blåsvær <sam@blaasvaer.dk>
|
|
5
5
|
* Version 1.0.0
|
|
@@ -10,16 +10,108 @@ global.routes = [];
|
|
|
10
10
|
global.ROUTE = function ( route, action, params = null ) {
|
|
11
11
|
let r = {
|
|
12
12
|
"controller": route.split('/')[1] == '' ? 'index' : route.split('/')[1],
|
|
13
|
+
"resource": route.split('/')[2] == '' ? 'index' : route.split('/')[2],
|
|
14
|
+
"resource_id": route.split('/')[3] == '' ? 'index' : route.split('/')[3],
|
|
13
15
|
"route": route,
|
|
14
16
|
"action": action,
|
|
15
17
|
"params": params,
|
|
16
18
|
}
|
|
17
|
-
// console.log("Router params:", params);
|
|
19
|
+
// console.log("Router params:", params?.type);
|
|
20
|
+
// console.log("----------------------");
|
|
21
|
+
// console.log("Router route:", route);
|
|
22
|
+
// console.log("Router controller:", r.controller);
|
|
23
|
+
// console.log("Router resource:", r.resource);
|
|
24
|
+
// console.log("Router resource_id:", r.resource_id);
|
|
25
|
+
// console.log("Router route:", r.route);
|
|
26
|
+
// console.log("Router action:", r.action);
|
|
27
|
+
// console.log("Router params:", r.params);
|
|
18
28
|
global.routes.push( r );
|
|
19
29
|
};
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
function Router ( req, url ) {
|
|
32
|
+
const method = req.method;
|
|
33
|
+
console.log("Router url:", url);
|
|
34
|
+
// Split url into array
|
|
35
|
+
let url_array = url.pathname.split('/');
|
|
36
|
+
|
|
37
|
+
// Remove first empty element
|
|
38
|
+
url_array.shift();
|
|
39
|
+
|
|
40
|
+
// Set controller, resource, resource_id, search, searchParams
|
|
41
|
+
this.controller = url_array[0];
|
|
42
|
+
this.resource = url_array[1];
|
|
43
|
+
this.resource_id = url_array[2];
|
|
44
|
+
this.search = url_array[3];
|
|
45
|
+
this.searchParams = url_array[4];
|
|
46
|
+
|
|
47
|
+
// console.log("referer", referer);
|
|
48
|
+
// console.log("url", url);
|
|
49
|
+
// console.log("this.controller", this.controller);
|
|
50
|
+
// console.log("this.resource", this.resource);
|
|
51
|
+
// console.log("this.resource_id", this.resource_id);
|
|
52
|
+
// console.log("this.search", this.search);
|
|
53
|
+
// console.log("this.searchParams", this.searchParams);
|
|
54
|
+
|
|
55
|
+
return this;
|
|
23
56
|
};
|
|
24
57
|
|
|
25
|
-
|
|
58
|
+
function findRoute ( url ) {
|
|
59
|
+
// Check if route exist
|
|
60
|
+
let route = global.routes.find( ( obj ) => obj.route === FW.utils.removeTrailingSlashes( url ) );
|
|
61
|
+
|
|
62
|
+
if ( route ) {
|
|
63
|
+
// console.log("Route defined", url);
|
|
64
|
+
// Execute action for route
|
|
65
|
+
return route;
|
|
66
|
+
} else {
|
|
67
|
+
const url_array = url.split('/').filter( e => e );
|
|
68
|
+
|
|
69
|
+
// Check if route is an API call
|
|
70
|
+
let isAPICall = url.split('/')[1] === 'api' ? true : false;
|
|
71
|
+
|
|
72
|
+
if ( isAPICall ) {
|
|
73
|
+
// console.log("Route NOT defined (API)", url, url.split('/')[1]);
|
|
74
|
+
/**
|
|
75
|
+
* If checking for UUID use:
|
|
76
|
+
* UUID v1:
|
|
77
|
+
* /^[0-9A-F]{8}-[0-9A-F]{4}-[1][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
78
|
+
* UUID v2:
|
|
79
|
+
* /^[0-9A-F]{8}-[0-9A-F]{4}-[2][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
80
|
+
* UUID v3:
|
|
81
|
+
* /^[0-9A-F]{8}-[0-9A-F]{4}-[3][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
82
|
+
* UUID v4:
|
|
83
|
+
* /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
84
|
+
* UUID v5:
|
|
85
|
+
* /^[0-9A-F]{8}-[0-9A-F]{4}-[5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
let regex = /()/;
|
|
89
|
+
|
|
90
|
+
switch ( url_array.length ) {
|
|
91
|
+
case 2:
|
|
92
|
+
regex = /api\/(?<resource>[a-z_]+)/; // match /api/<resource>
|
|
93
|
+
route = global.routes.find( ( obj ) => obj.route === '/api/:resources' );
|
|
94
|
+
break;
|
|
95
|
+
case 3:
|
|
96
|
+
regex = /api\/(?<resource>[a-z_]+)\/(?<id>[0-9]+)/; // match /api/<resource>/<id>
|
|
97
|
+
route = global.routes.find( ( obj ) => obj.route === '/api/:resources/:id' );
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let regex_result = url.match(regex);
|
|
102
|
+
let regex_groups = regex_result.groups;
|
|
103
|
+
|
|
104
|
+
route.resource = regex_groups.resource;
|
|
105
|
+
route.resource_id = regex_groups.id;
|
|
106
|
+
|
|
107
|
+
return route;
|
|
108
|
+
} else {
|
|
109
|
+
return global.routes.find( ( obj ) => obj.route === FW.utils.removeTrailingSlashes( url ) );
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = {
|
|
115
|
+
Router,
|
|
116
|
+
findRoute
|
|
117
|
+
}
|
package/views.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
const { readdir, readFile, stat } = require("fs").promises;
|
|
15
15
|
const { basename, join } = require("path");
|
|
16
|
+
|
|
16
17
|
/**
|
|
17
18
|
* 3rd party modules
|
|
18
19
|
*/
|
|
@@ -22,7 +23,7 @@ const htmlclean = require('htmlclean');
|
|
|
22
23
|
/**
|
|
23
24
|
* Custom modules
|
|
24
25
|
*/
|
|
25
|
-
const utils = require('
|
|
26
|
+
const utils = require('@blaasvaer/frmwrk/utils');
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Compile views on application initialization.
|
|
@@ -35,7 +36,12 @@ function Views ( config ) {
|
|
|
35
36
|
.isFile()
|
|
36
37
|
? readFile( path )
|
|
37
38
|
.then(function ( template ) {
|
|
38
|
-
let tpl = 'Handlebars.template(' + Handlebars.precompile(
|
|
39
|
+
let tpl = 'Handlebars.template(' + Handlebars.precompile( template.toString() ) + ')';
|
|
40
|
+
|
|
41
|
+
if ( config.compress_html ) {
|
|
42
|
+
tpl = 'Handlebars.template(' + Handlebars.precompile( htmlclean( template.toString() ) ) + ')';
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
return eval( tpl );
|
|
40
46
|
})
|
|
41
47
|
.catch(function ( err ) {
|
|
@@ -56,7 +62,6 @@ function Views ( config ) {
|
|
|
56
62
|
dir2obj ( views_dir )
|
|
57
63
|
.then( function ( output ) {
|
|
58
64
|
global.views = output;
|
|
59
|
-
// console.log('global.views:', global.views);
|
|
60
65
|
})
|
|
61
66
|
}
|
|
62
67
|
|