📜 ⬆️ ⬇️

WebSharper sitelets: creating a two-page website

Let me show you the simplest complete example using WebSharper sitelet, which will be in release 2.1.

Define a website of two pages (and two actions):
type Action = | Home | AboutUs 


view raw SiteletExample1.fs This Gist brought to you by GitHub.
Now let's mash up a website template using HTML combinators embedded in F #. A template is simply a function that receives the body and decorates it:

 module View = let ( => ) ab = A [HRef b] -< [Text a] let Page title body = PageContent <| fun ctx -> { Page.Default with Title = Some title Body = H1 [Text title] :: UL [ LI ["Home" => ctx.Link Home] LI ["AboutUs" => ctx.Link AboutUs] ] :: body } 

')
Two things must be noted:
  1. F # allows you to define your own syntax and example freely it uses (=>).
  2. Instead of manually generating URLs, you ask the context to create a link to the action. This provides security: if you rename the action Home, the project will no longer compile; if you move it to another URL, the links will remain correct.

Now we define the sitelets:
 module Site = let HomePage = View.Page "Home" [ Div [Text "Welcome to our website!"] ] |> Sitelet.Content "/" Home let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] ] |> Sitelet.Content "/about" AboutUs let Main = Sitelet.Sum [ HomePage AboutUsPage ] 

HomePage and AboutUsPage are one page URL URLs with one action. They are combined into a website using the Sum operator.
Now for a little administrative boilerplate:
 type Website() = interface IWebsite<Action> with member this.Actions = [] member this.Sitelet = Site.Main [<assembly: WebsiteAttribute(typeof<Website>)>] do () 

And that's it! Let's take a look at this:


So far so good. The pages have the URLs that we expected and the links in the menu work.
What is described above can be done with any decent web framework. Let's push the boundaries and season it a little. Add a few lines of F # that will be compiled into JavaScript:
 module Client = open IntelliFactory.WebSharper.Html [<JavaScript>] let Button label = Button [Text label] |>! OnClick (fun button _ -> button.Text <- "CLICKED") type ButtonControl(label: string) = inherit Web.Control() new () = new ButtonControl("unlabelled") [<JavaScript>] override this.Body = Button label :> _ 


There is a button that, when pressed, changes the inscription on itself. And there is a control.
Now, despite the fact that the Button lives entirely on the client (in fact, it creates DOM nodes), the Control performs a quantum transition: the designer runs on the server, and the body on the client.
But this means that you can use the Control to glue the client and server. Let's change the AboutUs page:

 let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] Div [new Client.ButtonControl("Click me!")] ] |> Sitelet.Content "/about" AboutUs 

Here it is. Now the user will see a push button with JavaScript implemented in F #, right where you expect it. No worries about script tags, no dependency catching, no worries with “ondocumentready”, everything just works:


Below is a full listing. As soon as version 2.1 comes out, you can run it yourself. Stay with us!
 namespace WebSharperSiteletsProject open System open System.IO open System.Web open IntelliFactory.Html open IntelliFactory.WebSharper open IntelliFactory.WebSharper.Sitelets type Action = | Home | AboutUs module View = let ( => ) ab = A [HRef b] -< [Text a] let Page title body = PageContent <| fun ctx -> { Page.Default with Title = Some title Body = H1 [Text title] :: UL [ LI ["Home" => ctx.Link Home] LI ["AboutUs" => ctx.Link AboutUs] ] :: body } module Client = open IntelliFactory.WebSharper.Html [<JavaScript>] let Button label = Button [Text label] |>! OnClick (fun button _ -> button.Text <- "CLICKED") type ButtonControl(label: string) = inherit Web.Control() new () = new ButtonControl("unlabelled") [<JavaScript>] override this.Body = Button label :> _ module Site = let HomePage = View.Page "Home" [ Div [Text "Welcome to our website!"] ] |> Sitelet.Content "/" Home let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] Div [new Client.ButtonControl("Click me!")] ] |> Sitelet.Content "/about" AboutUs let Main = Sitelet.Sum [ HomePage AboutUsPage ] type Website() = interface IWebsite<Action> with member this.Actions = [] member this.Sitelet = Site.Main [<assembly: WebsiteAttribute(typeof<Website>)>] do () 

Source: https://habr.com/ru/post/112651/


All Articles