Skip to content

Commit

Permalink
Added ViewEngine docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Lanayx committed Feb 14, 2024
1 parent f078d24 commit b53da6c
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- cron: "0 0 * * *"

env:
DOTNET_VERSION: 8.0.101
DOTNET_VERSION: 8.0.200

jobs:
build:
Expand Down
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.101"
"version": "8.0.200"
}
}
}
6 changes: 3 additions & 3 deletions src/Oxpecker.ViewEngine/Builder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ module Builder =

[<Struct>]
type HtmlElementType =
| NormalNode of dt: string
| VoidNode of st: string
| TextNode of text: TextNodeType
| NormalNode of nn: string
| VoidNode of vn: string
| TextNode of tn: TextNodeType
and [<Struct>] TextNodeType =
| RegularTextNode of reg: string
| RawTextNode of raw: string
Expand Down
108 changes: 103 additions & 5 deletions src/Oxpecker.ViewEngine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ Markup example:
```fsharp
open Oxpecker.ViewEngine
let staticHtml =
type Person = { Name: string }
let subView = p() { "Have a nice day" }
let renderView (model: Person) =
html() {
body(style = "width: 800px; margin: 0 auto") {
h1(style = "text-align: center; color: red") { "Error" }
p() { "Some long error text" }
body(style="width: 800px; margin: 0 auto") {
h1(style="text-align: center; color: red") {
$"Hello, {model.Name}!"
}
subView
ul() {
for i in 1..10 do
br()
li().attr("onclick", $"alert('Test {i}')") {
span(id= $"span{i}", class'="test") { $"Test {i}" }
}
Expand All @@ -24,4 +31,95 @@ let staticHtml =

## Documentation:

TBD
`Oxpecker.ViewEngine` is code-as-markup engine used to render your HTML views based on the F# feature called [Computation Expressions](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions).

- [HtmlElement](#htmlelement)
- [Children](#children)
- [Attributes](#attributes)
- [Event handlers](#event-handlers)
- [Html escaping](#html-escaping)
- [Rendering](#rendering)

### HtmlElement

`HtmlElement` is a main building block of `Oxpecker.ViewEngine`. It can be constructed from the instance of the `HtmlElementType`:

```fsharp
type HtmlElementType =
| NormalNode of string
| VoidNode of string
| TextNode of TextNodeType
```
This represents 3 types of Html elements: normal tags that have opening and closing part, void tags with no closint part and text nodes (which can be escaped and non-escaped strings).

All HTML tags inherit from `HtmlElement`, so you can easily add your own tag by in the same way:

```fsharp
type myTag() =
inherit HtmlElement("myTag")
```

`HtmlElement` holds two collections inside: attributes and children. More on them below.

### Children

Normal nodes can have children that will be added to children collection as you write them between curly braces. Void nodes and Text nodes don't have children. You can programmatically access `Chidren` property of any `HtmlElement`.

```fsharp
let result = div() {
br()
span() { "Some text" }
}
let children = result.Children // <br> and <span>
```

### Attributes

Normal and Void nodes can have attributes. Some general attributes are defined inside `HtmlElement` while each tag can have it's specific attributes. This will prevent you from assiging attributes to the element that it doesn't support. You can programmatically access `Attributes` property of any `HtmlElement`.

```fsharp
let result = div(class'="myClass") {
br(id="1234") // href attribute won't work here
a(href="/") { "Some link" }
}
let children = result.Attributes // myClass
```
You can also attach _any_ custom attribute to the `HtmlElement` using `.attr` method:

```fsharp
div().attr("data-secret-key", "lk23j4oij234"){
"Secret div"
}
```

### Event handlers

`Oxpecker.ViewEngine` doesn't provide support for javascript event handlers like `onclick`. This is done on purpose, since it would encourage people using them, which is rather an antipattern. However, if you really need it, you can always use `.attr` method to achieve same goal.

```fsharp
div().attr("onclick", "alert('Hello')"){
"Clickable div"
}
```


### HTML escaping

`Oxpecker.ViewEngine` will escape text nodes and attribute values for you. However, sometimes it's _desired_ to render unescaped html string, in that case `raw` function is provided

```fsharp
div(){
"<script></script>" // This will be escaped
raw "<script></script>" // This will NOT be escaped
}
```

### Rendering

There are several functions to render `HtmlElement` (after opening Oxpecker.ViewEngine namespace):

- **Render.toString** will render to standard .NET UTF16 string
- **Render.toBytes** will render to UTF8-encoded byte array
- **Render.toHtmlDocBytes** is the same as **Render.toBytes**, but will also prepend `"<!DOCTYPE html>"` to the HTML document

0 comments on commit b53da6c

Please sign in to comment.