Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F3893704
mountable-with-fields.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
3 KB
Referenced Files
None
Subscribers
None
mountable-with-fields.ts
View Options
import
{
ShapeToType
}
from
"@sealcode/ts-predicates"
;
import
{
Context
}
from
"koa"
;
import
{
FlatTemplatable
,
tempstream
}
from
"tempstream"
;
import
{
FormControl
}
from
"../forms/controls/form-control"
;
import
{
FieldsToShape
,
FormField
}
from
"../forms/fields/field"
;
import
{
FormData
,
FormDataValue
,
FormMessage
}
from
"../forms/form"
;
import
{
Mountable
}
from
"./mountable"
;
export
type
PageErrorMessage
=
{
type
:
"access"
|
"internal"
;
message
:
string
};
export
type
Fields
=
Record
<
string
,
FormField
<
boolean
,
unknown
>>
;
export
abstract
class
MountableWithFields
<
F
extends
Fields
=
Fields
>
extends
Mountable
{
fields
:
F
;
field_names_prefix
=
""
;
// useful for multiform, where many forms are merged into one and field assignment is made using the prefix
form_id
=
""
;
// all fields within this mountable will be tied to form of this id
abstract
controls
:
FormControl
[];
constructor
()
{
super
();
if
(
!
this
.
fields
)
this
.
fields
=
{}
as
F
;
}
init
()
:
void
{
for
(
const
[
name
,
field
]
of
Object
.
entries
(
this
.
fields
))
{
field
.
init
(
name
);
}
}
// this one is meant to be overwritten
async
validateValues
(
ctx
:
Context
,
data
:
Record
<
string
,
FormDataValue
>
)
:
Promise
<
{
valid
:
boolean
;
error
:
string
}
>
{
return
{
valid
:
true
,
error
:
""
,
};
}
async
validate
(
ctx
:
Context
,
values
:
Record
<
string
,
FormDataValue
>
)
:
Promise
<
{
valid
:
boolean
;
field_errors
:
Partial
<
Record
<
keyof
Fields
,
string
>>
;
form_messages
:
FormMessage
[];
}
>
{
const
field_errors
=
{}
as
Record
<
keyof
Fields
,
string
>
;
let
valid
=
true
;
const
form_messages
=
[]
as
FormMessage
[];
await
Promise
.
all
(
Object
.
entries
(
values
)
.
filter
(([
fieldname
])
=>
fieldname
in
this
.
fields
)
.
map
(
async
([
key
]
:
[
keyof
F
,
FormDataValue
])
=>
{
const
field
=
this
.
fields
[
key
];
const
{
valid
:
fieldvalid
,
message
:
fieldmessage
}
=
await
field
.
getValue
(
ctx
,
values
);
if
(
!
fieldvalid
)
{
valid
=
false
;
field_errors
[
field
.
name
]
=
fieldmessage
;
}
})
);
const
formValidationResult
=
await
this
.
validateValues
(
ctx
,
values
);
if
(
!
formValidationResult
.
valid
)
{
form_messages
.
push
({
type
:
"error"
,
text
:
formValidationResult
.
error
,
});
valid
=
false
;
}
return
{
valid
,
field_errors
,
form_messages
};
}
public
renderControls
(
ctx
:
Context
,
data
:
FormData
<
keyof
Fields
>
,
validate
:
boolean
)
:
FlatTemplatable
{
return
tempstream
/* HTML */
`
${
this
.
controls
.
map
((
control
)
=>
control
.
render
(
ctx
,
data
.
raw_values
,
data
.
messages
,
this
.
field_names_prefix
,
this
.
form_id
,
validate
)
)
}
`
;
}
async
renderError
(
_
:
Context
,
error
:
PageErrorMessage
)
:
Promise
<
FlatTemplatable
>
{
return
error
.
message
;
}
public
renderMessages
(
_
:
Context
,
data
:
FormData
<
keyof
Fields
>
)
:
FlatTemplatable
{
return
tempstream
/* HTML */
`<div class="form-messages">
${
data
.
messages
.
map
(
(
message
)
=>
`<div class="form-message form-message--
${
message
.
type
}
">
${
message
.
text
}
</div>`
)
}
</div>`
;
}
abstract
extractRawValues
(
ctx
:
Context
)
:
Promise
<
Record
<
string
,
FormDataValue
>>
;
async
getParsedValues
(
ctx
:
Context
)
:
Promise
<
ShapeToType
<
FieldsToShape
<
F
>>>
{
const
raw_values
=
await
this
.
extractRawValues
(
ctx
);
const
result
:
Record
<
string
,
unknown
>
=
{};
const
promises
=
Object
.
entries
(
this
.
fields
).
map
(
async
([
key
,
field
])
=>
{
const
{
parsed
}
=
await
field
.
getValue
(
ctx
,
raw_values
);
result
[
key
]
=
parsed
;
}
);
await
Promise
.
all
(
promises
);
return
result
as
ShapeToType
<
FieldsToShape
<
F
>>
;
}
async
getDatabaseValues
(
ctx
:
Context
)
:
Promise
<
ShapeToType
<
FieldsToShape
<
F
>>>
{
const
raw_values
=
await
this
.
extractRawValues
(
ctx
);
const
result
:
Record
<
string
,
unknown
>
=
{};
const
promises
=
Object
.
entries
(
this
.
fields
).
map
(
async
([
key
,
field
])
=>
{
const
db_value
=
await
field
.
getDatabaseValue
(
ctx
,
raw_values
);
if
(
db_value
!==
undefined
)
{
result
[
key
]
=
db_value
;
}
}
);
await
Promise
.
all
(
promises
);
return
result
as
ShapeToType
<
FieldsToShape
<
F
>>
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-java
Expires
Mon, May 19, 00:52 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
635681
Default Alt Text
mountable-with-fields.ts (3 KB)
Attached To
Mode
rSGEN sealgen
Attached
Detach File
Event Timeline
Log In to Comment