diff --git a/.psscripts/build-functions.ps1 b/.psscripts/build-functions.ps1 index 84791817..4920c373 100644 --- a/.psscripts/build-functions.ps1 +++ b/.psscripts/build-functions.ps1 @@ -2,24 +2,6 @@ # Generic functions # ---------------------------------------------- -function Test-IsMonoInstalled -{ - <# - .DESCRIPTION - Checks to see whether the current environment has the Mono framework installed. - - .EXAMPLE - if (Test-IsMonoInstalled) { Write-Host "Mono is available." } - #> - - try - { - $result = Invoke-Cmd "mono --version" -Silent - return $result.StartsWith("Mono JIT compiler version") - } - catch { return false } -} - function Get-UbuntuVersion { <# @@ -210,32 +192,11 @@ function Get-NetCoreTargetFrameworks ($projFile) Get-TargetFrameworks $projFile | Where-Object { $_ -like "netstandard*" -or $_ -like "netcoreapp*" } } -function Invoke-DotNetCli ($cmd, $proj, $argv) -{ - # Currently dotnet test does not work for net461 on Linux/Mac - # See: https://github.com/Microsoft/vstest/issues/1318 - - if((!($IsWindows) -and !(Test-IsMonoInstalled)) ` - -or (!($IsWindows) -and ($cmd -eq "test"))) - { - $netCoreFrameworks = Get-NetCoreTargetFrameworks($proj) - - foreach($fw in $netCoreFrameworks) { - $fwArgv = "-f $fw " + $argv - Invoke-Cmd "dotnet $cmd $proj $fwArgv" - } - } - else - { - Invoke-Cmd "dotnet $cmd $proj $argv" - } -} - function dotnet-info { Invoke-Cmd "dotnet --info" -Silent } function dotnet-version { Invoke-Cmd "dotnet --version" -Silent } function dotnet-restore ($project, $argv) { Invoke-Cmd "dotnet restore $project $argv" } -function dotnet-build ($project, $argv) { Invoke-DotNetCli -Cmd "build" -Proj $project -Argv $argv } -function dotnet-test ($project, $argv) { Invoke-DotNetCli -Cmd "test" -Proj $project -Argv $argv } +function dotnet-build ($project, $argv) { Invoke-Cmd "dotnet build $project $argv" } +function dotnet-test ($project, $argv) { Invoke-Cmd "dotnet test $project $argv" } function dotnet-run ($project, $argv) { Invoke-Cmd "dotnet run --project $project $argv" } function dotnet-pack ($project, $argv) { Invoke-Cmd "dotnet pack $project $argv" } function dotnet-publish ($project, $argv) { Invoke-Cmd "dotnet publish $project $argv" } diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 77facb84..a465d4de 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -38,13 +38,6 @@ An in depth functional reference to all of Giraffe's default features. - [Response Caching](#response-caching) - [Response Compression](#response-compression) - [Giraffe View Engine](#giraffe-view-engine) - - [HTML Elements and Attributes](#html-elements-and-attributes) - - [Text Content](#text-content) - - [Naming Convention](#naming-convention) - - [View Engine Best Practices](#view-engine-best-practices) - - [Custom Elements and Attributes](#custom-elements-and-attributes) - - [Rendering Views](#rendering-views) - - [Common View Engine Features](#common-view-engine-features) - [Serialization](#serialization) - [JSON](#json) - [XML](#xml) @@ -2643,6 +2636,8 @@ dict [ ] ``` +In addition to the `DefaultNegotiationConfig`, there is also a `JsonOnlyNegotiationConfig` provided which only returns JSON. + As you can see from the example above the default dictionary uses the `json` and `xml` http handlers to define the response handler for the respective media types. If a client requests a `text/plain` response then a new function had to be created which accepts an `obj` and uses the `.ToString()` method in combination with the `text` http handler to return a plain text response. If a client has no particular preference (`*/*`) then the default response is `json`. @@ -2918,457 +2913,19 @@ ASP.NET Core has its own [Response Compression Middleware](https://docs.microsof ## Giraffe View Engine -Giraffe has its own functional view engine which can be used to build rich UIs for web applications. The single biggest and best contrast to other view engines (e.g. Razor, Liquid, etc.) is that the Giraffe View Engine is entirely functional written in normal (and compiled) F# code. +Giraffe has its own functional view engine which can be used to build rich UIs for web applications. The single biggest and best contrast to other view engines (e.g. Razor, Liquid, etc.) is that the Giraffe View Engine is entirely functional, written in normal (and compiled) F# code. This means that the Giraffe View Engine is by definition one of the most feature rich view engines available, requires no disk IO to load a view and views are automatically compiled at build time. The Giraffe View Engine uses traditional functions and F# record types to generate rich HTML/XML views. -### HTML Elements and Attributes - -HTML elements and attributes are defined as F# objects: - -```fsharp -let indexView = - html [] [ - head [] [ - title [] [ str "Giraffe Sample" ] - ] - body [] [ - h1 [] [ str "I |> F#" ] - p [ _class "some-css-class"; _id "someId" ] [ - str "Hello World" - ] - ] - ] -``` - -A HTML element can either be a `ParentNode`, a `VoidElement` or a `Text` element. - -For example the `` or `
` tags are typical `ParentNode` elements. They can hold an `XmlAttribute list` and a second `XmlElement list` for their child elements: - -```fsharp -let someHtml = div [] [] -``` - -All `ParentNode` elements accept these two parameters: - -```fsharp -let someHtml = - div [ _id "someId"; _class "css-class" ] [ - a [ _href "https://example.org" ] [ str "Some text..." ] - ] -``` - -Most HTML tags are `ParentNode` elements, however there is a few HTML tags which cannot hold any child elements, such as `
`, `
` or `` tags. These are represented as `VoidElement` objects and only accept the `XmlAttribute list` as single parameter: - -```fsharp -let someHtml = - div [] [ - br [] - hr [ _class "css-class-for-hr" ] - p [] [ str "bla blah" ] - ] -``` - -Attributes are further classified into two different cases. First and most commonly there are `KeyValue` attributes: - -```fsharp -a [ - _href "http://url.com" - _target "_blank" - _class "class1" ] [ str "Click here" ] -``` - -As the name suggests, they have a key, such as `class` and a value such as the name of a CSS class. - -The second category of attributes are `Boolean` flags. There are not many but some HTML attributes which do not require any value (e.g. `async` or `defer` in script tags). The presence of such an attribute means that the feature is turned on, otherwise it is turned off: - -```fsharp -script [ _src "some.js"; _async ] [] -``` - -There's also a wealth of [accessibility attributes](https://www.w3.org/TR/html-aria/) available under the `Giraffe.GiraffeViewEngine.Accessibility` module (needs to be explicitly opened). - -### Text Content - -Naturally the most frequent content in any HTML document is pure text: - -```html -
-

This is text content

-

This is even more text content!

-
-``` - -The Giraffe View Engine lets one create pure text content as a `Text` element. A `Text` element can either be generated via the `rawText` or `encodedText` (or the short alias `str`) functions: - -```fsharp -let someHtml = - div [] [ - p [] [ rawText "
Hello World
" ] - p [] [ encodedText "
Hello World
" ] - ] -``` - -The `rawText` function will create an object of type `XmlNode` where the content will be rendered in its original form and the `encodedText`/`str` function will output a string where the content has been HTML encoded. - -In this example the first `p` element will literally output the string as it is (`
Hello World
`) while the second `p` element will output the value as HTML encoded string `<div>Hello World</div>`. - -Please be aware that the the usage of `rawText` is mainly designed for edge cases where someone would purposefully want to inject HTML (or JavaScript) code into a rendered view. If not used carefully this could potentially lead to serious security vulnerabilities and therefore should be used only when explicitly required. - -Most cases and particularly any user provided content should always be output via the `encodedText`/`str` function. - -### Javascript event handlers - -It is possible to add JavaScript event handlers to HTML elements using the Giraffe View Engine. These event handlers (all prefixed with names starting with `_on`, for example `_onclick`, `_onmouseover`) can either execute inline JavaScript code or can invoke functions that are part of the `window` scope. - -This example illustrates how inline JavaScript could be used to log to the console when a button is clicked: - -```fsharp -let inlineJSButton = - button [_id "inline-js" - _onclick "console.log(\"Hello from the 'inline-js' button!\");"] [str "Say Hello" ] -``` - -There are some caveats with this approach, namely that -* it is not very scalable to write JavaScript inline in this manner, and more pressing -* the Giraffe View Engine HTML-encodes the text provided to the `_onX` attributes. - -To get around this, you can write dedicated scripts in your HTML and reference the functions from your event handlers: - -```fsharp -let page = - div [] [ - script [_type "application/javascript"] [ - rawText """ - window.greet = function () { - console.log("ping from the greet method"); - } - """ - ] - button [_id "script-tag-js" - _onclick "greet();"] [str "Say Hello"] - ] -``` - -Here it's important to note that we've included the text of our script using the `rawText` tag. This ensures that our text is not encoded by Giraffe so that it remains as we have written it. - -However, writing large quantities of JavaScript in this manner can be difficult, because you don't have access to the large ecosystem of javascript editor tooling. In this case you should write your functions in another script and use a `script` tag element to reference your script, then add the desired function to your HTML element's event handler. - -Say you had a JavaScript file named `greet.js` and had configured Giraffe to serve that script from the WebRoot. Let us also say that the content of that script was: - -```javascript -function greet() { - console.log("Hello from the greet function of greet.js!"); -} -``` - -Then, you could reference that javascript via a script element, and use `greet` in your event handler like so: - -```fsharp -let page = - html [] [ - head [] [ - script [_type "application/javascript" - _src "/greet.js"] [] // include our `greet.js` function dynamically - ] - body [] [ - button [_id "greet-btn" - _onclick "greet()"] [] // use the `greet()` function from `greet.js` to say hello - ] - ] -``` - -In this way, you can write `greet.js` with all of your expected tooling, and still hook up the event handlers all in one place in Giraffe. - -### Naming Convention - -The Giraffe View Engine has a naming convention which lets you easily determine the correct function name without having to know anything about the view engine's implementation. - -All HTML tags are defined as `XmlNode` elements under the exact same name as they are named in HTML. For example the `` tag would be `html [] []`, an `` tag would be `a [] []` and a `` or `` would be the `span [] []` or `canvas [] []` function. - -HTML attributes follow the same naming convention except that attributes have an underscore prepended. For example the `class` attribute would be `_class` and the `src` attribute would be `_src` in Giraffe. - -The underscore does not only help to distinguish an attribute from an element, but also avoid a naming conflict between tags and attributes of the same name (e.g. `
` vs. ``). - -If a HTML attribute has a hyphen in the name (e.g. `accept-charset`) then the equivalent Giraffe attribute would be written in camel case notion (e.g. `acceptCharset`). - -*Should you find a HTML tag or attribute missing in the Giraffe View Engine then you can either [create it yourself](#custom-elements-and-attributes) or send a [pull request on GitHub](https://github.com/giraffe-fsharp/Giraffe/pulls).* - -### View Engine Best Practices - -Due to the huge amount of available HTML tags and their fairly generic (and short) names (e.g. ``, `