jQuery Mobile page reuse with Websharper Core team

I have been reworking an older WebSharper jQuery Mobile app which used one sitelet (compiled to HTML file) for each JQM page. I decided to use another approach: a single-page application with JQM pages generated lazily and reused if needed. JQM has a sample which that gives an example of page reuse, so I implemented it with WebSharper. The resulting framework is easy to expand and manage.



First some helper functions for building page content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace Sample

open IntelliFactory.WebSharper
open IntelliFactory.WebSharper.JQuery
open IntelliFactory.WebSharper.JQuery.Mobile
open IntelliFactory.WebSharper.Html

[<JavaScript>]
module App =
    let mobile = Mobile.Instance

    let HeaderDiv cont =
        Div [ HTML5.Attr.Data "role" "header" ] -< cont

    let ContentDiv cont =
        Div [ HTML5.Attr.Data "role" "content" ] -< cont

    let PageDiv id' cont =
        Div [
            HTML5.Attr.Data "role" "page"
            Id id'
        ] -< cont |>! OnAfterRender (fun el ->
            JQuery.Of el.Body |> Mobile.Page.Init
        ) 

    let ListViewUL cont =
        UL [
            HTML5.Attr.Data "role" "listview"
            HTML5.Attr.Data "inset" "true"
        ] -< cont   

Then the sample data, now stored locally, but it could be modified easily to make a web request for example using WebSharper's automatic RPC implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//module App continued
    type CategoryData =
        {
            Name        : string
            Description : string
            Items       : string list
        }

    let getCategoryData category =
        match category with
        | "animals" -> Some { 
                Name = "Animals"
                Description = "All your favorites from aardvarks to zebras."
                Items = [ "Pets"; "Farm Animals"; "Wild Animals" ] }
        | "colors" -> Some { 
                Name = "Colors"
                Description = "Fresh colors from the magic rainbow."
                Items = [ "Blue"; "Green"; "Orange"; "Purple"; "Red"; "Yellow"; "Violet" ] }
        | "vehicles" -> Some { 
                Name = "Vehicles"
                Description = "Everything from cars to planes."
                Items = [ "Cars"; "Planes"; "Construction" ] }
        | _ -> None

Now, lets define the pages. A simple record can contain the DOM element of the page, and a function that should be run on page load (first use and reuse too). It returns a bool deciding if we should proceed with the page change or cancel it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//module App continued
    type JQMPage =
        {
            Html: Element
            Load: unit -> bool
        }

    // Page Ids
    module Ids =
        let [<Literal>] HomePage  = "home"
        let [<Literal>] ItemsPage = "items"
    module Refs =
        let [<Literal>] HomePage  = "#home"
        let [<Literal>] ItemsPage = "#items"

    // State
    let mutable selectedCategory = None

    let HomePage =
        let createListItem category text =
            LI [
                A [ HRef ""; Text text ]
                |>! OnClick (fun _ _ ->
                    selectedCategory <- Some category    
                    Refs.ItemsPage |> mobile.ChangePage
                )
            ] 
        {
            Html =
                PageDiv Ids.HomePage [
                    HeaderDiv [ H1 [ Text "Categories" ] ]
                    ContentDiv [
                        H2 [ Text "Select a Category Below:" ]
                        ListViewUL [
                            createListItem "animals"  "Animals"
                            createListItem "colors"   "Colors"
                            createListItem "vehicles" "Vehicles"
                        ]
                    ]
                ] 
            Load = fun() -> true
        }

    let ItemsPage =
        lazy
        let title = H1 []
        let description = P []
        let itemsList = ListViewUL []
        {
            Html =
                PageDiv Ids.ItemsPage [
                    HTML5.Attr.Data "add-back-btn" "true" ] -< [
                    HeaderDiv [ title ]
                    ContentDiv [
                        description 
                        ListViewUL [ itemsList ]
                    ]
                ]
            Load = fun() ->
                match getCategoryData selectedCategory.Value with
                | Some categoryData ->
                    title.Text <- categoryData.Name
                    description.Text <- categoryData.Description
                    itemsList.Clear()
                    categoryData.Items |> List.iter (fun i -> (LI [Text i]) |> itemsList.Append)
                    JQuery.Of itemsList.Body |> Mobile.ListView.Refresh
                    true
                | None -> false
        }
        
    let getJQMPage pageRef =
        match pageRef with
        | Refs.HomePage  -> Some HomePage
        | Refs.ItemsPage -> Some ItemsPage.Value
        | _ -> None

Any pages can be initialized lazily, so the app loads as fast as possible. We will want to load the #home page when the application starts, so there it is not needed. The helper function getJQMPage matches the inner page hash URLs to the JQMPage records we defined.

Finally we have to define a Web.Control which handles the creating of pages on page change requests and loads the #home page initially. The event handler for PageBeforeChange checks if the DOM node for the required page has been inserted already and initializes it if it has'nt been. If Load() would return false we cancel the page change.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type AppControl() =
    inherit Web.Control()

    [<JavaScript>]
    override this.Body =
        Mobile.Events.PageBeforeChange.On(JQuery.Of Dom.Document.Current, fun (e, data) ->
            match data.ToPage with
            | :? string as pageUrl -> 
                match App.getJQMPage pageUrl with
                | Some pageObj ->
                    let body = JQuery.Of "body"                  
                    let toPage =
                        match body.Children pageUrl with
                        | p when p.Length = 0 ->
                            let page = pageObj.Html
                            body.Append page.Body |> ignore
                            (page :> IPagelet).Render()
                            JQuery.Of page.Body
                        | p -> p
                    if not (pageObj.Load()) then e.PreventDefault()
                | None _ -> ()
            | _ -> ()
        )
        upcast Div [] |>! OnAfterRender (fun _ -> App.Refs.HomePage |> App.mobile.ChangePage)

WebSharper allows for an easy composition of dynamically created pages which can make creating mobile apps a quick and fun process.

WebSharper, PhoneGap, and Ripple: easier native HTML5 apps Core team

We are experimenting with PhoneGap, PhoneGap Build, Ripple emulator and WebSharper. If successful, this will let you write truly cross-platform native mobile apps in F#, quickly pre-testing them in Chrome, and then generating various installers (Android, Windows, iOS - yes, iOS!) without even having to install the SDK. Current mobile HTML 5 application story is this: either you create a mobile-friendly website and have users navigate to it, or you wrap your HTML 5 app into a native app - th[...]
>> Read the full article on t0yv0.blogspot.com

TypeScript: initial impressions Core team

There are several things under the TypeScript umbrella: a type system, language spec, JavaScript-targeting compiler and tooling that provides interactive code completion. I have tried TypeScript on a few small projects, the latest one being TypedPhoneGap. I also worked extensively with the language spec, wrote a parser and analyzer for the `.d.ts` contract specification fragment, pondered the semantics, and engaged in little flamewars on the language forum. My conclusion, in short, is this: the[...]
>> Read the full article on t0yv0.blogspot.com

WebSharper: From F# power features to JavaScript interop Core team

I recently gave a talk at MLOC-JS about binding JavaScript libraries for use in WebSharper. Several people reported that the video posted was hard to navigate, clicking on the timeline caused the audio and the video go out of sync. Thanks to the helpful folks at Ustream, this problem was quickly fixed and the updated video from the talk is available at (same place as before):

WebSharper: From F# power features to JavaScript interop (includes a sneak preview of CloudSharper!)

Enjoy!

Automate, automate, automate.. Core team

Latest snapshot of the WebSharper repositories (Bitbucket and at GitHub) showcases some build automation I finally managed to get working. It starts from MSBuild that uses NuGet to pull dependencies, including build dependencies, and then jumps to FAKE - using the alpha pre-release FAKE version has solved some F# version problems I faced earlier. It builds a lot of code, creates an output NuGet package, and also creates several Visual Studio templates that it packages up into a VSIX extensibil[...]
>> Read the full article on t0yv0.blogspot.com

WebSharper for Windows 8 Desktop Core team

In addition to increasingly popular web applications, HTML and JavaScript-based applications have also made an appearance on the desktop with Windows 8. The WinJS API allows the creation of full-blown Windows 8 desktop applications combining the rich built-in features of Windows 8 and the tremendous capabilities of existing JavaScript libraries.

And of course, where HTML and JavaScript run, so does WebSharper :) We are therefore happy to announce the upcoming release of WebSharper for Windows 8 Desktop. This will include full WinJS bindings as well as a set of Visual Studio templates to get you quickly started with the development of desktop applications with WebSharper.

As a preview of the capabilities offered by WebSharper for Windows 8 Desktop, we are releasing a simple yet inclusive application on the Windows Store.



This is a simple function plotting application that demonstrates the combined use of Windows 8 styles and controls and JavaScript goodness.

The above screenshot shows the HTML5 Canvas used to draw the functions, Windows 8-styled titles and buttons, as well as Windows 8 specific controls such as the ListView for the history panel on the right.

The screenshot below features an external JavaScript library, MathJax, which renders mathematical equations using TeX's robust layout algorithm.



We are very much looking forward to putting WebSharper for Windows 8 Desktop in your hands to see what you can do with it!

WebSharper 2.5.2-alpha on AppHarbor Core team

Pre-release WebSharper 2.5.2-alpha NuGet package is available and can already be used to build AppHarbor-ready sites. AppHarbor is an attractive execution environment for WebSharper apps: its provides a free basic option, and builds and executes your code in the cloud (using Amazon EC2). The basic option does not come with default permanent storage, but we found that combining it with Windows Azure storage service is entirely viable. Small projects will incur 0 monthly cost because of Azure free storage quota.

Up until now, running WebSharper on AppHarbor without committing the binaries has been a bit quirky. This is finally resolved, and here is a sample ready-to-clone application:
websharper-bootstrap-site. We are now finalizing testing the 2.5 WebSharper release and working on preparing a matching extensions release. In the meanwhile, you can already try to start your own cloud-based WebSharper site with AppHarbor and the alpha package.

Your comments and suggestions on how to improve the app are very welcome.

Upcoming WebSharper Changes Core team

It is time for some long-awaited improvements in WebSharper: Direct API and TypeScript cross-compiler.

Direct API


While working on the CloudSharper (WebSharper IDE) project, we strongly felt the need to have a more flexible way to call into WebSharper, to have the compiler as a service. In particular, we wanted it to be able to compile code on the fly inside an FSI session, including parsing FSI-defined dynamic assemblies. While very reasonable in retrospect, this requirement was not on the table in the original design, and we had to put in quite a few changes to make it work. The good news is that it is working, and you can even compile F# to JavaScript inside an FSI session. The changes are already published in our official WebSharper repository, in particular see FrontEnd.fsi. I am now finalizing some cleanup tasks and will soon release a NuGet package update incorporating the changes.

Direct API makes a few frequently requested scenarios much easier. For example, it is now a lot more straightforward to avoid reliance on ASP.NET, to build more flexible tools, or to do things like targeting Node and a pure-JavaScript runtime.

TypeScript



In case you have not noticed, there is a new language from Microsoft called TypeScript. After working with deciphering its semantics for a bit, I am not a big fan of TypeScript design (this deserves another blog); but I will grant that it is a vast improvement on JavaScript. Moreover, TypeScript defines a standard way to describe JavaScript library interfaces, and people have started doing so en masse, see for example DefinitelyTyped. With the TypeScript cross-compiler tool we are trying to reuse all this work - and generate WebSharper FFI bindings based on TypeScript ".d.ts" files, using either a F# 3.0 TypeProvider or bulid-time API. A competing project, FunScript, has pioneered the approach.

TypeScript bindings are likely to be the future of WebSharper extensions story, even though the quality of the present TypeScript bindings strikes me as very poor. Well, so does the quality of TypeScript definition language. TypeScript does not, for instance, allow generics in the specifications, though they are considering to add them in the next release. Regardless, the reason that TypeScript bindings are exciting is social - due to excellent tooling and Microsoft backing TypeScript is picking up very quickly. There are already many more TS bindings than WebSharper bindings, and given the dynamic of its adoption, their quality is likely to improve quickly. We would like to ride the wave.

Free WebSharper MVP licenses Core team

As F# is making its headway into becoming a true mainstream language, we are more committed than ever to facilitate this journey and bring F# to ALL web and mobile developers.

As of today, we are happy to announce that we are offering a free WebSharper developer license for all language and web MVPs - a $600 dollar value for free!

To claim yours, simply send your name, MVP specialization and MVP number to:

websharper-mvp at intellifactory.com

WebSharper is an open source web framework that makes web development fun, easy and robust. Want safe URLs, type-safe web forms, or composable web applications? Then WebSharper is for you! Download your copy today, and work with the most versatile .NET web framework to develop your web and web-based mobile applications quicker and with less code than ever before.

If you are wondering about licensing - it's actually as easy as it can be: Having a developer license enables you to develop CLOSED source applications (regardless of whether they are premium or not) with WebSharper. However, if you are an open source developer, you do not need a developer license to use WebSharper - and it is still free and will remain free forever!

You can also contribute to WebSharper. Currently, development takes place in two separate repositories: the public one and the support one. The latter is where all upcoming features and bugfixes are tested before they are rolled out to the public repository in bi-annual code drops. We are working on merging these repositories to give developers the latest and greatest, and also taking pull requests from the community.

Running the jQuery Mobile WebSharper sample Core team

The jQuery Mobile sample on the WebSharper site has been out for quite some time now, but it fails to mention an important detail on how to run it standalone. Indeed, copying it straight into a new WebSharper ASP.NET project produces an empty page (which is not empty, only jQuery Mobile fails to kick in to decorate it into a full application), which can be a discouraging start for anyone looking into using jQuery Mobile for building mobile applications with F# and WebSharper.

What's not shown in that sample is that the sample runner sitelet adds a container div and a "dummy" jQuery Mobile page for the dynamic "paging" mechanism to work. So when you copy-and-paste the sample code into a new application, you need to add that same wrapper yourself. In case you are starting from a WebSharper ASP.NET template, you need to modify the ASPX file as follows:
1
2
3
4
5
6
7
8
...
<body>
     <div>
            <div data-role="page" id="dummy"></div>
            <ws:MyControl ID="MyControl1" runat="server"/>
     </div>
...
Hope this helps.