structured-fw 0.8.42 → 0.8.44
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 +21 -8
- package/package.json +10 -3
- package/app/models/README.md +0 -9
- package/app/routes/README.md +0 -19
- package/app/views/README.md +0 -1
- package/app/views/layout.html +0 -1
- package/build/Config.d.ts +0 -2
- package/build/Config.js +0 -30
- package/build/app/Types.d.ts +0 -5
- package/build/app/Types.js +0 -1
- package/build/app/global.d.ts +0 -3
- package/build/app/global.js +0 -1
- package/build/app/models/Users.d.ts +0 -0
- package/build/app/models/Users.js +0 -1
- package/build/app/routes/Auth.d.ts +0 -0
- package/build/app/routes/Auth.js +0 -1
- package/build/app/routes/Test.d.ts +0 -2
- package/build/app/routes/Test.js +0 -101
- package/build/app/routes/Todo.d.ts +0 -0
- package/build/app/routes/Todo.js +0 -1
- package/build/app/routes/Upload.d.ts +0 -0
- package/build/app/routes/Upload.js +0 -1
- package/build/app/routes/Validation.d.ts +0 -2
- package/build/app/routes/Validation.js +0 -34
- package/build/app/routess/Auth.d.ts +0 -0
- package/build/app/routess/Auth.js +0 -1
- package/build/app/routess/Test.d.ts +0 -2
- package/build/app/routess/Test.js +0 -101
- package/build/app/routess/Todo.d.ts +0 -0
- package/build/app/routess/Todo.js +0 -1
- package/build/app/routess/Upload.d.ts +0 -0
- package/build/app/routess/Upload.js +0 -1
- package/build/app/routess/Validation.d.ts +0 -2
- package/build/app/routess/Validation.js +0 -34
- package/build/app/views/components/ClientImport/ClientImport.client.d.ts +0 -2
- package/build/app/views/components/ClientImport/ClientImport.client.js +0 -4
- package/build/app/views/components/ClientImport/Export.d.ts +0 -1
- package/build/app/views/components/ClientImport/Export.js +0 -1
- package/build/app/views/components/Conditionals/Conditionals.client.d.ts +0 -2
- package/build/app/views/components/Conditionals/Conditionals.client.js +0 -43
- package/build/app/views/components/FormTest/FormTestNested/FormTestNested.d.ts +0 -8
- package/build/app/views/components/FormTest/FormTestNested/FormTestNested.js +0 -7
- package/build/app/views/components/ModelsTest/ModelsTest.client.d.ts +0 -2
- package/build/app/views/components/ModelsTest/ModelsTest.client.js +0 -5
- package/build/app/views/components/MultipartForm/MultipartForm.client.d.ts +0 -0
- package/build/app/views/components/MultipartForm/MultipartForm.client.js +0 -1
- package/build/app/views/components/PassObject/PassObject.d.ts +0 -10
- package/build/app/views/components/PassObject/PassObject.js +0 -10
- package/build/app/views/components/PassObject/ReceiveObj/ReceiveObj.d.ts +0 -6
- package/build/app/views/components/PassObject/ReceiveObj/ReceiveObj.js +0 -6
- package/build/app/views/components/RedrawAbort/RedrawAbort.client.d.ts +0 -2
- package/build/app/views/components/RedrawAbort/RedrawAbort.client.js +0 -6
- package/build/app/views/components/RedrawAbort/RedrawAbort.d.ts +0 -8
- package/build/app/views/components/RedrawAbort/RedrawAbort.js +0 -8
- package/build/app/views/components/ServerSideContext/ServerSideContext.d.ts +0 -7
- package/build/app/views/components/ServerSideContext/ServerSideContext.js +0 -10
- package/build/assets/ts/Export.d.ts +0 -1
- package/build/assets/ts/Export.js +0 -1
- package/build/index.d.ts +0 -1
- package/build/index.js +0 -8
- package/build/tsconfig.tsbuildinfo +0 -1
- package/jsr.json +0 -35
- package/system/EventEmitter.ts +0 -38
- package/system/Helpers.ts +0 -97
- package/system/Symbols.ts +0 -6
- package/system/Types.ts +0 -232
- package/system/Util.ts +0 -488
- package/system/bin/structured.ts +0 -115
- package/system/client/App.ts +0 -11
- package/system/client/Client.ts +0 -9
- package/system/client/ClientComponent.ts +0 -1107
- package/system/client/DataStore.ts +0 -101
- package/system/client/DataStoreView.ts +0 -82
- package/system/client/Net.ts +0 -58
- package/system/client/NetRequest.ts +0 -64
- package/system/global.d.ts +0 -12
- package/system/server/Application.ts +0 -239
- package/system/server/Component.ts +0 -409
- package/system/server/Components.ts +0 -114
- package/system/server/Cookies.ts +0 -29
- package/system/server/Document.ts +0 -163
- package/system/server/DocumentHead.ts +0 -150
- package/system/server/FormValidation.ts +0 -231
- package/system/server/Handlebars.ts +0 -51
- package/system/server/Request.ts +0 -502
- package/system/server/Session.ts +0 -151
- package/system/server/dom/DOMFragment.ts +0 -7
- package/system/server/dom/DOMNode.ts +0 -140
- package/system/server/dom/HTMLParser.ts +0 -238
- package/tsconfig.json +0 -31
package/README.md
CHANGED
|
@@ -41,6 +41,17 @@ npm install @types/node
|
|
|
41
41
|
### Create boilerplate
|
|
42
42
|
`npx structured init`
|
|
43
43
|
|
|
44
|
+
### Create a test route
|
|
45
|
+
Create a file `/app/routes/Test.ts`:
|
|
46
|
+
```
|
|
47
|
+
import { Application } from 'structured-fw/Application';
|
|
48
|
+
export default function(app: Application) {
|
|
49
|
+
app.request.on('GET', '/test', async()=> {
|
|
50
|
+
return 'Hello, World!';
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
44
55
|
### Compile
|
|
45
56
|
`tsc`\
|
|
46
57
|
This will create a directory `build` (or whatever you have in tsconfig.json as compilerOptions.outputDir)
|
|
@@ -57,6 +68,8 @@ cd build
|
|
|
57
68
|
pm2 start index.js --name="[appName]"
|
|
58
69
|
```
|
|
59
70
|
|
|
71
|
+
If you followed the above steps, you should be able to access `http://localhost:9191/test` in your browser and see the output `Hello, World!`.
|
|
72
|
+
|
|
60
73
|
# Key concepts
|
|
61
74
|
|
|
62
75
|
## Application
|
|
@@ -418,7 +431,7 @@ That was the simplest possible example, let's make it more interesting by adding
|
|
|
418
431
|
### Component server-side code
|
|
419
432
|
Create a new file `/app/views/HelloWorld/HelloWorld.ts` (server side component code):
|
|
420
433
|
```
|
|
421
|
-
import { ComponentScaffold } from '
|
|
434
|
+
import { ComponentScaffold } from 'structured-fw/Types';
|
|
422
435
|
export default class HelloWorld implements ComponentScaffold {
|
|
423
436
|
async getData(): Promise<{
|
|
424
437
|
luckyNumber: number
|
|
@@ -460,7 +473,7 @@ Let's make it even more interesting by adding some client side code to it.
|
|
|
460
473
|
### Component client-side code
|
|
461
474
|
Create `/app/views/HelloWorld/HelloWorld.client.ts`:
|
|
462
475
|
```
|
|
463
|
-
import { InitializerFunction } from '
|
|
476
|
+
import { InitializerFunction } from 'structured-fw/Types';
|
|
464
477
|
export const init: InitializerFunction = async function() {
|
|
465
478
|
const generateNew = this.ref<HTMLButtonElement>('newNumber');
|
|
466
479
|
|
|
@@ -509,7 +522,7 @@ Parent says your lucky number is {{number}}.
|
|
|
509
522
|
That's it. Since `AnotherComponent` has no server side code, all data passed to it is exported to HTML, hence the `number` you passed from `HelloWorld` will be readily available for use. If AnotherComponent had a server side part, the process is a bit different, it will receive it as part of the `data`, but can choose whether to make it available to the HTML, or just make use of it and return other stuff. Let's see how that works.
|
|
510
523
|
Create `/app/views/AnotherComponent/AnotherComponent.ts`:
|
|
511
524
|
```
|
|
512
|
-
import { ComponentScaffold } from '
|
|
525
|
+
import { ComponentScaffold } from 'structured-fw/Types';
|
|
513
526
|
export default class AnotherComponent implements ComponentScaffold {
|
|
514
527
|
async getData(data: { number: number }): Promise<{
|
|
515
528
|
parentSuggests: number,
|
|
@@ -542,7 +555,7 @@ What about client side? **By default, data returned by server side code is not a
|
|
|
542
555
|
|
|
543
556
|
Let's create a client side code for `AnotherComponent` and export the `betterNumber` to it, create `/app/views/AnotherComponent/AnotherComponent.client.ts`:
|
|
544
557
|
```
|
|
545
|
-
import { InitializerFunction } from '
|
|
558
|
+
import { InitializerFunction } from 'structured-fw/Types';
|
|
546
559
|
export const init: InitializerFunction = async function() {
|
|
547
560
|
const betterNumber = this.getData<number>('betterNumber');
|
|
548
561
|
|
|
@@ -552,7 +565,7 @@ export const init: InitializerFunction = async function() {
|
|
|
552
565
|
|
|
553
566
|
And let's update `AnotherComponent.ts` to export `betterNumber`:
|
|
554
567
|
```
|
|
555
|
-
import { ComponentScaffold } from '
|
|
568
|
+
import { ComponentScaffold } from 'structured-fw/Types';
|
|
556
569
|
export default class AnotherComponent implements ComponentScaffold {
|
|
557
570
|
exportFields = ['betterNumber'];
|
|
558
571
|
async getData(data: { number: number }): Promise<{
|
|
@@ -574,7 +587,7 @@ This concept is wrong to start with, if we want a component to be independent, i
|
|
|
574
587
|
|
|
575
588
|
Let's say we wanted to access the `parent` Component from `AnotherComponent`:
|
|
576
589
|
```
|
|
577
|
-
import { InitializerFunction } from '
|
|
590
|
+
import { InitializerFunction } from 'structured-fw/Types';
|
|
578
591
|
export const init: InitializerFunction = async function() {
|
|
579
592
|
const betterNumber = this.getData<number>('betterNumber');
|
|
580
593
|
|
|
@@ -585,7 +598,7 @@ Here we accessed the `parent` and obtained it's `name`.
|
|
|
585
598
|
|
|
586
599
|
*"But we did not send any data to the parent here"* - correct, we did not, and we won't, instead we can inform them we have some data available, or that an event they might be interested in has occurred, and if they care, so be it:
|
|
587
600
|
```
|
|
588
|
-
import { InitializerFunction } from '
|
|
601
|
+
import { InitializerFunction } from 'structured-fw/Types';
|
|
589
602
|
export const init: InitializerFunction = async function() {
|
|
590
603
|
const betterNumber = this.getData<number>('betterNumber');
|
|
591
604
|
|
|
@@ -595,7 +608,7 @@ export const init: InitializerFunction = async function() {
|
|
|
595
608
|
|
|
596
609
|
We emitted an `event` with `eventName` = "`truth`" and a `payload`, which in this case is a string, but can be of any type. If the parent cares about it (or for that matter, not necessarily the parent, but anyone in the component tree), they can subscribe to that event. Let's subscribe to the event from `HelloWorld` (`HelloWorld.client.ts`):
|
|
597
610
|
```
|
|
598
|
-
import { InitializerFunction } from '
|
|
611
|
+
import { InitializerFunction } from 'structured-fw/Types';
|
|
599
612
|
export const init: InitializerFunction = async function() {
|
|
600
613
|
|
|
601
614
|
const child = this.find('AnotherComponent'); // ClientComponent | null
|
package/package.json
CHANGED
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "build/index",
|
|
17
|
-
"version": "0.8.
|
|
17
|
+
"version": "0.8.44",
|
|
18
18
|
"scripts": {
|
|
19
19
|
"develop": "tsc --watch",
|
|
20
20
|
"startDev": "cd build && nodemon --watch '../app/**/*' --watch '../build/**/*' -e js,html,css index.js",
|
|
21
21
|
"start": "cd build && node index.js",
|
|
22
|
-
"prepublish": "tsc"
|
|
23
|
-
"postinstall": "rm tsconfig.json"
|
|
22
|
+
"prepublish": "tsc"
|
|
24
23
|
},
|
|
25
24
|
"bin": {
|
|
26
25
|
"structured": "./build/system/bin/structured.js"
|
|
@@ -35,6 +34,14 @@
|
|
|
35
34
|
"mime-types": "^3.0.0",
|
|
36
35
|
"ts-md5": "^1.3.1"
|
|
37
36
|
},
|
|
37
|
+
"files": [
|
|
38
|
+
"build/system/*",
|
|
39
|
+
"app/Types.ts",
|
|
40
|
+
"index.ts",
|
|
41
|
+
"Config.ts",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
38
45
|
"exports" : {
|
|
39
46
|
"./Types": "./build/system/Types.js",
|
|
40
47
|
"./Symbols": "./build/system/Symbols.js",
|
package/app/models/README.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
You don't have to use this directory, but if you are keen on MVC concept, this would be the place for your models.
|
|
2
|
-
|
|
3
|
-
There are not specific rules for these files. They are never loaded automaticallt by the framework, instead you should
|
|
4
|
-
load them where you want to use them.
|
|
5
|
-
|
|
6
|
-
Usually a model will export a class or a class instance, but it could be a function, set of functions, or anything really.
|
|
7
|
-
|
|
8
|
-
Models are meant to abstract the logic and data layer for a specific entity of your app. For example a web shop would likely
|
|
9
|
-
have a model Product.ts which exports a class with methods such as create(productData: ProductData) to create a new product and delete(productId: number) to delete an existing product.
|
package/app/routes/README.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Routes:
|
|
2
|
-
|
|
3
|
-
You can add routes directly in index.ts using app.request.on
|
|
4
|
-
but in order to avoid clutter and keep the code structured, you should add the routes here (/app/routes)
|
|
5
|
-
|
|
6
|
-
All files in this directory will be loaded once the server is started,
|
|
7
|
-
so feel free to separate your routes in as many files as you feel makes sense, eg. it would make sense
|
|
8
|
-
to have Auth.ts that would add routes for everything auth related, such as /login, /register, etc...
|
|
9
|
-
|
|
10
|
-
Example:
|
|
11
|
-
|
|
12
|
-
export default async function(app: Application) {
|
|
13
|
-
|
|
14
|
-
app.request.on('GET', '/login', async (ctx) => {
|
|
15
|
-
// ctx is a RequestContext
|
|
16
|
-
ctx.response.write('Login page');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
}
|
package/app/views/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Place for pages and components
|
package/app/views/layout.html
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{{{layoutComponent component data attributes}}}
|
package/build/Config.d.ts
DELETED
package/build/Config.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export const config = {
|
|
2
|
-
envPrefix: 'STRUCTURED',
|
|
3
|
-
autoInit: true,
|
|
4
|
-
url: {
|
|
5
|
-
removeTrailingSlash: true,
|
|
6
|
-
componentRender: '/componentRender',
|
|
7
|
-
isAsset: function (uri) {
|
|
8
|
-
return uri.indexOf('/assets/') === 0;
|
|
9
|
-
}
|
|
10
|
-
},
|
|
11
|
-
routes: {
|
|
12
|
-
path: '/app/routes'
|
|
13
|
-
},
|
|
14
|
-
components: {
|
|
15
|
-
path: '/app/views',
|
|
16
|
-
componentNameAttribute: 'structured-component'
|
|
17
|
-
},
|
|
18
|
-
session: {
|
|
19
|
-
cookieName: 'session',
|
|
20
|
-
keyLength: 24,
|
|
21
|
-
durationSeconds: 60 * 60,
|
|
22
|
-
garbageCollectIntervalSeconds: 60
|
|
23
|
-
},
|
|
24
|
-
http: {
|
|
25
|
-
port: 9191,
|
|
26
|
-
host: '0.0.0.0',
|
|
27
|
-
linkHeaderRel: 'preload'
|
|
28
|
-
},
|
|
29
|
-
runtime: 'Node.js'
|
|
30
|
-
};
|
package/build/app/Types.d.ts
DELETED
package/build/app/Types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/build/app/global.d.ts
DELETED
package/build/app/global.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
File without changes
|
package/build/app/routes/Auth.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
package/build/app/routes/Test.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { Document } from '../../system/server/Document.js';
|
|
2
|
-
import { Request } from '../../system/server/Request.js';
|
|
3
|
-
export default function (app) {
|
|
4
|
-
app.request.on('GET', '/test/form', async (ctx) => {
|
|
5
|
-
const doc = new Document(app, 'Form test', ctx);
|
|
6
|
-
await doc.loadComponent('FormTestNested', { test: 3 });
|
|
7
|
-
return doc;
|
|
8
|
-
});
|
|
9
|
-
app.request.on('POST', '/test/form', async (ctx) => {
|
|
10
|
-
console.log(JSON.stringify(ctx.body, undefined, 4));
|
|
11
|
-
const userImage = ctx.files.user.image[0];
|
|
12
|
-
ctx.response.setHeader('Content-Type', userImage.type);
|
|
13
|
-
ctx.respondWith(userImage.data);
|
|
14
|
-
});
|
|
15
|
-
app.request.on('GET', '/test/client_import', async (ctx) => {
|
|
16
|
-
const doc = new Document(app, 'Test', ctx);
|
|
17
|
-
await doc.loadComponent('ClientImport', { xyz: 10, asd: 12 });
|
|
18
|
-
ctx.respondWith(doc);
|
|
19
|
-
});
|
|
20
|
-
app.request.on('GET', '/test/redraw', async (ctx) => {
|
|
21
|
-
const doc = new Document(app, 'Test', ctx);
|
|
22
|
-
await doc.loadComponent('RedrawAbort');
|
|
23
|
-
ctx.respondWith(doc);
|
|
24
|
-
});
|
|
25
|
-
app.request.on('GET', '/test/models', async (ctx) => {
|
|
26
|
-
const doc = new Document(app, 'Test', ctx);
|
|
27
|
-
await doc.loadComponent('ModelsTest');
|
|
28
|
-
ctx.respondWith(doc);
|
|
29
|
-
});
|
|
30
|
-
app.request.on('GET', '/getargs', async (ctx) => {
|
|
31
|
-
ctx.respondWith(ctx.getArgs);
|
|
32
|
-
});
|
|
33
|
-
app.request.on('GET', '/form/multipart', async (ctx) => {
|
|
34
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
35
|
-
await doc.loadComponent('MultipartForm');
|
|
36
|
-
ctx.respondWith(doc);
|
|
37
|
-
});
|
|
38
|
-
app.request.on('POST', '/form/multipart', async (ctx) => {
|
|
39
|
-
console.log(ctx.files);
|
|
40
|
-
ctx.respondWith(ctx.body);
|
|
41
|
-
});
|
|
42
|
-
app.request.on('GET', '/conditional', async (ctx) => {
|
|
43
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
44
|
-
await doc.loadComponent('Conditionals');
|
|
45
|
-
ctx.respondWith(doc);
|
|
46
|
-
});
|
|
47
|
-
app.request.on('GET', '/urldecode', async (ctx) => {
|
|
48
|
-
const noVal = 'noVal';
|
|
49
|
-
const noValNested = 'filters[beds][min]';
|
|
50
|
-
const simple = 'simple=2';
|
|
51
|
-
const simpleObj = 'person[name]=fname&person[last_name]=lname';
|
|
52
|
-
const simpleArray = 'colors[]=red&colors[]=blue';
|
|
53
|
-
const orderedArray = 'colorsOrdered[1]=red&colorsOrdered[0]=blue';
|
|
54
|
-
const indexedArray = 'months[0]=Jan&months[1]=Feb&months[2]=Mar';
|
|
55
|
-
const arrayOfObjects = 'users[0][name]=John&users[0][email]=johndoe@gmail.com&users[1][name]=Tim&users[1][email]=tim@gmail.com';
|
|
56
|
-
const objectWithArrayValues = 'user[name]=John&user[last_name]=Doe&user[sports][]=table tennis&user[sports][]=football';
|
|
57
|
-
const objectWithObjectValues = 'data[paper][props][size]=10x13&data[paper][props][type]=matte';
|
|
58
|
-
const nestedArraySimple = 'colorStack[0][]=red&colorStack[0][]=blue&colorStack[1][]=green';
|
|
59
|
-
const arrayOfObjectsWithArrayValues = 'usersArr[0][name]=John&usersArr[0][email]=johndoe@gmail.com&usersArr[0][sports][]=football&usersArr[0][sports][]=basketball&usersArr[1][name]=Too&usersArr[1][email]=tootoo@gmail.com&usersArr[1][sports][]=bocce&usersArr[1][sports][]=cricket&usersArr[1][sports][]=dancing';
|
|
60
|
-
const missingValue = 'missing=';
|
|
61
|
-
const missingArrayValue = 'missingArr[]=';
|
|
62
|
-
const objBlankValue = `objBlank[0][email]=`;
|
|
63
|
-
const spaces = `spaces=value%20with%20spaces`;
|
|
64
|
-
const special = `garbage=` + encodeURIComponent('value!@#&$%^*()');
|
|
65
|
-
const nonLatin = `key3=` + encodeURIComponent('привет');
|
|
66
|
-
const t = new Date().getTime();
|
|
67
|
-
const test = Request.queryStringDecode([noVal, noValNested, simple, simpleObj, simpleArray, orderedArray, indexedArray, arrayOfObjects, objectWithArrayValues, objectWithObjectValues, nestedArraySimple, arrayOfObjectsWithArrayValues, missingValue, nonLatin, spaces, special, objBlankValue, missingArrayValue, simple].join('&'));
|
|
68
|
-
const dur = new Date().getTime() - t;
|
|
69
|
-
console.log(dur);
|
|
70
|
-
ctx.respondWith(test);
|
|
71
|
-
});
|
|
72
|
-
app.request.on('GET', '/client_import', async (ctx) => {
|
|
73
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
74
|
-
await doc.loadComponent('ClientImport');
|
|
75
|
-
doc.head.add(`
|
|
76
|
-
<script type="importmap">
|
|
77
|
-
{
|
|
78
|
-
imports: {
|
|
79
|
-
'components/*' : '/build/app/views/components/*'
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
</script>
|
|
83
|
-
`);
|
|
84
|
-
ctx.respondWith(doc);
|
|
85
|
-
});
|
|
86
|
-
app.request.on('GET', '/serverclass', async (ctx) => {
|
|
87
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
88
|
-
await doc.loadComponent('ServerSideContext');
|
|
89
|
-
ctx.respondWith(doc);
|
|
90
|
-
});
|
|
91
|
-
app.request.on('GET', '/routes/new', async (ctx) => {
|
|
92
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
93
|
-
await doc.loadComponent('Conditionals');
|
|
94
|
-
return doc;
|
|
95
|
-
});
|
|
96
|
-
app.request.on('GET', '/passObj', async (ctx) => {
|
|
97
|
-
const doc = new Document(app, 'Test pass obj', ctx);
|
|
98
|
-
await doc.loadComponent('PassObject');
|
|
99
|
-
ctx.respondWith(doc);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
File without changes
|
package/build/app/routes/Todo.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { FormValidation } from '../../system/server/FormValidation.js';
|
|
2
|
-
import { Document } from "../../system/server/Document.js";
|
|
3
|
-
export default function (app) {
|
|
4
|
-
let validator = new FormValidation();
|
|
5
|
-
validator.singleError = true;
|
|
6
|
-
validator.addRule('name', 'Name', ['required', ['minLength', 3]]);
|
|
7
|
-
validator.addRule('email', 'Email', ['validEmail']);
|
|
8
|
-
validator.addRule('number', 'Number', ['number', 'required']);
|
|
9
|
-
validator.addRule('numeric', 'Numeric', ['numeric', 'required']);
|
|
10
|
-
validator.addRule('float', 'Float', ['float', 'required']);
|
|
11
|
-
app.request.on('POST', '/validation', async (ctx) => {
|
|
12
|
-
if (ctx.body) {
|
|
13
|
-
let validationResult = await validator.validate(ctx.body);
|
|
14
|
-
if (validationResult.valid) {
|
|
15
|
-
ctx.response.write('Valid');
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
app.session.setValue(ctx.sessionId, 'validationErrors', validationResult.errors);
|
|
19
|
-
app.session.setValue(ctx.sessionId, 'formValues', ctx.body);
|
|
20
|
-
app.request.redirect(ctx.response, '/validation');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
app.request.on('GET', '/validation', async (ctx) => {
|
|
25
|
-
let doc = new Document(app, 'Form validation');
|
|
26
|
-
await doc.loadView('pages/validation', app.session.extract(ctx.sessionId, [
|
|
27
|
-
{ validationErrors: 'errors' },
|
|
28
|
-
{ formValues: 'values' }
|
|
29
|
-
]));
|
|
30
|
-
ctx.response.write(doc.toString());
|
|
31
|
-
app.session.removeValue(ctx.sessionId, 'validationErrors');
|
|
32
|
-
app.session.removeValue(ctx.sessionId, 'formValues');
|
|
33
|
-
});
|
|
34
|
-
}
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { Document } from '../../system/server/Document.js';
|
|
2
|
-
import { Request } from '../../system/server/Request.js';
|
|
3
|
-
export default function (app) {
|
|
4
|
-
app.request.on('GET', '/test/form', async (ctx) => {
|
|
5
|
-
const doc = new Document(app, 'Form test', ctx);
|
|
6
|
-
await doc.loadComponent('FormTestNested', { test: 3 });
|
|
7
|
-
ctx.respondWith(doc);
|
|
8
|
-
});
|
|
9
|
-
app.request.on('POST', '/test/form', async (ctx) => {
|
|
10
|
-
console.log(JSON.stringify(ctx.body, undefined, 4));
|
|
11
|
-
const userImage = ctx.files.user.image[0];
|
|
12
|
-
ctx.response.setHeader('Content-Type', userImage.type);
|
|
13
|
-
ctx.respondWith(userImage.data);
|
|
14
|
-
});
|
|
15
|
-
app.request.on('GET', '/test/client_import', async (ctx) => {
|
|
16
|
-
const doc = new Document(app, 'Test', ctx);
|
|
17
|
-
await doc.loadComponent('ClientImport', { xyz: 10, asd: 12 });
|
|
18
|
-
ctx.respondWith(doc);
|
|
19
|
-
});
|
|
20
|
-
app.request.on('GET', '/test/redraw', async (ctx) => {
|
|
21
|
-
const doc = new Document(app, 'Test', ctx);
|
|
22
|
-
await doc.loadComponent('RedrawAbort');
|
|
23
|
-
ctx.respondWith(doc);
|
|
24
|
-
});
|
|
25
|
-
app.request.on('GET', '/test/models', async (ctx) => {
|
|
26
|
-
const doc = new Document(app, 'Test', ctx);
|
|
27
|
-
await doc.loadComponent('ModelsTest');
|
|
28
|
-
ctx.respondWith(doc);
|
|
29
|
-
});
|
|
30
|
-
app.request.on('GET', '/getargs', async (ctx) => {
|
|
31
|
-
ctx.respondWith(ctx.getArgs);
|
|
32
|
-
});
|
|
33
|
-
app.request.on('GET', '/form/multipart', async (ctx) => {
|
|
34
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
35
|
-
await doc.loadComponent('MultipartForm');
|
|
36
|
-
ctx.respondWith(doc);
|
|
37
|
-
});
|
|
38
|
-
app.request.on('POST', '/form/multipart', async (ctx) => {
|
|
39
|
-
console.log(ctx.files);
|
|
40
|
-
ctx.respondWith(ctx.body);
|
|
41
|
-
});
|
|
42
|
-
app.request.on('GET', '/conditional', async (ctx) => {
|
|
43
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
44
|
-
await doc.loadComponent('Conditionals');
|
|
45
|
-
ctx.respondWith(doc);
|
|
46
|
-
});
|
|
47
|
-
app.request.on('GET', '/urldecode', async (ctx) => {
|
|
48
|
-
const noVal = 'noVal';
|
|
49
|
-
const noValNested = 'filters[beds][min]';
|
|
50
|
-
const simple = 'simple=2';
|
|
51
|
-
const simpleObj = 'person[name]=fname&person[last_name]=lname';
|
|
52
|
-
const simpleArray = 'colors[]=red&colors[]=blue';
|
|
53
|
-
const orderedArray = 'colorsOrdered[1]=red&colorsOrdered[0]=blue';
|
|
54
|
-
const indexedArray = 'months[0]=Jan&months[1]=Feb&months[2]=Mar';
|
|
55
|
-
const arrayOfObjects = 'users[0][name]=John&users[0][email]=johndoe@gmail.com&users[1][name]=Tim&users[1][email]=tim@gmail.com';
|
|
56
|
-
const objectWithArrayValues = 'user[name]=John&user[last_name]=Doe&user[sports][]=table tennis&user[sports][]=football';
|
|
57
|
-
const objectWithObjectValues = 'data[paper][props][size]=10x13&data[paper][props][type]=matte';
|
|
58
|
-
const nestedArraySimple = 'colorStack[0][]=red&colorStack[0][]=blue&colorStack[1][]=green';
|
|
59
|
-
const arrayOfObjectsWithArrayValues = 'usersArr[0][name]=John&usersArr[0][email]=johndoe@gmail.com&usersArr[0][sports][]=football&usersArr[0][sports][]=basketball&usersArr[1][name]=Too&usersArr[1][email]=tootoo@gmail.com&usersArr[1][sports][]=bocce&usersArr[1][sports][]=cricket&usersArr[1][sports][]=dancing';
|
|
60
|
-
const missingValue = 'missing=';
|
|
61
|
-
const missingArrayValue = 'missingArr[]=';
|
|
62
|
-
const objBlankValue = `objBlank[0][email]=`;
|
|
63
|
-
const spaces = `spaces=value%20with%20spaces`;
|
|
64
|
-
const special = `garbage=` + encodeURIComponent('value!@#&$%^*()');
|
|
65
|
-
const nonLatin = `key3=` + encodeURIComponent('привет');
|
|
66
|
-
const t = new Date().getTime();
|
|
67
|
-
const test = Request.queryStringDecode([noVal, noValNested, simple, simpleObj, simpleArray, orderedArray, indexedArray, arrayOfObjects, objectWithArrayValues, objectWithObjectValues, nestedArraySimple, arrayOfObjectsWithArrayValues, missingValue, nonLatin, spaces, special, objBlankValue, missingArrayValue, simple].join('&'));
|
|
68
|
-
const dur = new Date().getTime() - t;
|
|
69
|
-
console.log(dur);
|
|
70
|
-
ctx.respondWith(test);
|
|
71
|
-
});
|
|
72
|
-
app.request.on('GET', '/client_import', async (ctx) => {
|
|
73
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
74
|
-
await doc.loadComponent('ClientImport');
|
|
75
|
-
doc.head.add(`
|
|
76
|
-
<script type="importmap">
|
|
77
|
-
{
|
|
78
|
-
imports: {
|
|
79
|
-
'components/*' : '/build/app/views/components/*'
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
</script>
|
|
83
|
-
`);
|
|
84
|
-
ctx.respondWith(doc);
|
|
85
|
-
});
|
|
86
|
-
app.request.on('GET', '/serverclass', async (ctx) => {
|
|
87
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
88
|
-
await doc.loadComponent('ServerSideContext');
|
|
89
|
-
ctx.respondWith(doc);
|
|
90
|
-
});
|
|
91
|
-
app.request.on('GET', '/routes/new', async (ctx) => {
|
|
92
|
-
const doc = new Document(app, 'Test multipart form', ctx);
|
|
93
|
-
await doc.loadComponent('Conditionals');
|
|
94
|
-
return doc;
|
|
95
|
-
});
|
|
96
|
-
app.request.on('GET', '/passObj', async (ctx) => {
|
|
97
|
-
const doc = new Document(app, 'Test pass obj', ctx);
|
|
98
|
-
await doc.loadComponent('PassObject');
|
|
99
|
-
ctx.respondWith(doc);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { FormValidation } from '../../system/server/FormValidation.js';
|
|
2
|
-
import { Document } from "../../system/server/Document.js";
|
|
3
|
-
export default function (app) {
|
|
4
|
-
let validator = new FormValidation();
|
|
5
|
-
validator.singleError = true;
|
|
6
|
-
validator.addRule('name', 'Name', ['required', ['minLength', 3]]);
|
|
7
|
-
validator.addRule('email', 'Email', ['validEmail']);
|
|
8
|
-
validator.addRule('number', 'Number', ['number', 'required']);
|
|
9
|
-
validator.addRule('numeric', 'Numeric', ['numeric', 'required']);
|
|
10
|
-
validator.addRule('float', 'Float', ['float', 'required']);
|
|
11
|
-
app.request.on('POST', '/validation', async (ctx) => {
|
|
12
|
-
if (ctx.body) {
|
|
13
|
-
let validationResult = await validator.validate(ctx.body);
|
|
14
|
-
if (validationResult.valid) {
|
|
15
|
-
ctx.response.write('Valid');
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
app.session.setValue(ctx.sessionId, 'validationErrors', validationResult.errors);
|
|
19
|
-
app.session.setValue(ctx.sessionId, 'formValues', ctx.body);
|
|
20
|
-
app.request.redirect(ctx.response, '/validation');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
app.request.on('GET', '/validation', async (ctx) => {
|
|
25
|
-
let doc = new Document(app, 'Form validation');
|
|
26
|
-
await doc.loadView('pages/validation', app.session.extract(ctx.sessionId, [
|
|
27
|
-
{ validationErrors: 'errors' },
|
|
28
|
-
{ formValues: 'values' }
|
|
29
|
-
]));
|
|
30
|
-
ctx.response.write(doc.toString());
|
|
31
|
-
app.session.removeValue(ctx.sessionId, 'validationErrors');
|
|
32
|
-
app.session.removeValue(ctx.sessionId, 'formValues');
|
|
33
|
-
});
|
|
34
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const test = 1;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const test = 1;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export const init = async function () {
|
|
2
|
-
const style = document.createElement('style');
|
|
3
|
-
style.type = 'text/css';
|
|
4
|
-
style.textContent = `
|
|
5
|
-
.active {
|
|
6
|
-
font-weight: 800;
|
|
7
|
-
}
|
|
8
|
-
`;
|
|
9
|
-
document.head.appendChild(style);
|
|
10
|
-
this.store.set('showMessage', false);
|
|
11
|
-
this.bind(this.ref('setShowMessage'), 'click', () => {
|
|
12
|
-
this.store.set('showMessage', true);
|
|
13
|
-
});
|
|
14
|
-
this.bind(this.ref('unsetShowMessage'), 'click', () => {
|
|
15
|
-
this.store.set('showMessage', false);
|
|
16
|
-
});
|
|
17
|
-
let num = 0;
|
|
18
|
-
const increaseNum = () => {
|
|
19
|
-
num++;
|
|
20
|
-
setNum();
|
|
21
|
-
};
|
|
22
|
-
const decreaseNum = () => {
|
|
23
|
-
num--;
|
|
24
|
-
setNum();
|
|
25
|
-
};
|
|
26
|
-
const setNum = () => {
|
|
27
|
-
this.store.set('number', num);
|
|
28
|
-
this.ref('num').textContent = num.toString();
|
|
29
|
-
};
|
|
30
|
-
this.bind(this.ref('numIncrease'), 'click', () => {
|
|
31
|
-
increaseNum();
|
|
32
|
-
});
|
|
33
|
-
this.bind(this.ref('numDecrease'), 'click', () => {
|
|
34
|
-
decreaseNum();
|
|
35
|
-
});
|
|
36
|
-
setNum();
|
|
37
|
-
this.conditionalCallback('method1', () => {
|
|
38
|
-
return this.store.get('showMessage') === true && num > 3;
|
|
39
|
-
});
|
|
40
|
-
this.conditionalCallback('method2', (number) => {
|
|
41
|
-
return number === num;
|
|
42
|
-
});
|
|
43
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ComponentScaffold, RequestContext } from '../../../../../system/Types.js';
|
|
2
|
-
type ComponentData = {
|
|
3
|
-
test: number;
|
|
4
|
-
};
|
|
5
|
-
export default class FormTestNested implements ComponentScaffold {
|
|
6
|
-
getData(data: ComponentData, ctx: RequestContext): Promise<ComponentData>;
|
|
7
|
-
}
|
|
8
|
-
export {};
|