sergei-mironov / urweb-etab

Simple web-based archery competitions calendar written in Ur/Web
0 stars 0 forks source link

Thank you for these examples #1

Open StefanScott opened 9 years ago

StefanScott commented 9 years ago

SUMMARY:

Because you are actively programming in Ur/Web on practical projects, reading your code is very helpful for beginners like me to learn typical idioms and good style.

Perhaps you may someday also find some time to publish some annotations or commentaries to some of your code.

Although much of it may seem "obvious" to you - any commentaries regarding your code may be quite novel and instructive to beginner Ur/Web programmers such as myself.

I am really a beginner with Ur/Web - but I have studied functional languages such as ML and Haskell a lot.

The language I use mostly has been Maude - which is similar to ML and Haskell (differences: Maude has subtypes; it is first-level, not higher-level; and Maude's modules can contain axioms, unlike ML modules).

Thank you for sharing these contributions. I will continue to study them.

Well, I've been asking for nice idioms and your Etab.ur certainly has many nice idioms.

I am reading it more closely now and learning a lot :-)

https://github.com/grwlf/urweb-etab/blob/master/Etab.ur

I had of course repeatedly skimmed the grwlf/etab repository (apparently modeling archery competitions) 3-4 times in the past few months, expecting that (along with your other works ecosat and oil-price) I might be seeing some good examples there to learn from.

I had also looked a few times at your uru3 and urweb-soup and urweb-prelude.

I did not yet use them because I was afraid of possible additional complications due to the cake file - but perhaps I should learn to adapt to this as a necessity for building larger Ur/Web applications, as you have.

I have some initial basic questions:

(1) Your code uses a cake file, based on Haskell.

So I should first also install Haskell, in order to use Etab, correct?

(2) The purpose of this function:

https://github.com/grwlf/urweb-soup/blob/dcd4131a5cf2b51154c4c432fd8c263c1175f4fa/Unsafe.urs

Is to allow the programmer to include arbitrary HTML fragments in the HTML output from the Ur/Web compiler, correct?

These s2xhead and s2xbody functions were contributed by you then?

I was expecting that s2xhead and s2xbody would specify the concrete location to "splice in" the resulting HTML fragments - but now I see that it these functions merely do some kind of "wrapping".

Now I see that the specification of the location where to "splice in" the fragment of course simply occurs at the particular location of insertion of value 'donate' (which calls Unsafe.s2xbody), towards the end, here:

        </ul>
        {donate}
        </p>
      </xml>

Some other interesting idioms I am noticing:

Idiom 1: Blessing a directory.

I didn't know you could just do this, and assign the result to a value.

But of course this makes sense now: bless isn't some exceptional syntax, it is merely a function call, and returns a useful value.

val srcprj = bless "https://github.com/grwlf/urweb-etab"

Idiom 2: It is interesting that you aren't even use an SQL database at all. Just using native ML-style data types.

This is fascinating and encouraging to me.

UPDATE: Ah I see later you do use an SQL database - and you have interesting DML code to interface between the ML-style datatypes, and the SQL.

Idiom 3:

fun template_ w links mb : transaction page =
  let
  Uru.run (
  JQuery.add (
  Bootstrap.add (
  Soup.layout {Width=w} (fn nar =>
  Uru.withStylesheet (Etab_css.url) (
  Uru.withHeader

As mentioned above, I had looked at the uru3 repository a few times in the past months. I guess I got intimidated by the cake file, and wanted to avoid using any extra layers in my initial, minimal (ie, "Hello World") attempts to implement some sort of autocomplete widget in Ur/Web.

Now I also recall that any cake file is simply necessary 'glue' code to put files together at the OS level, and I see that the cake dialect being used is Haskell (not C), so I understand that I should just have my cake and eat it too.

Questions regarding cake:

It seems that cake3 is your invention, correct?

I will have to install Haskell to use it, correct?

(I have installed Haskell a few times in the past, but now I am on a new Debian machine with almost nothing - only Ur/Web. I imagine it is now time to install Haskell too.)

Idiom 4: This is interesting, suggesting that the most important thing to capture or know (ie parameterize) about any Layout is its width.

Soup.layout {Width=w}

Questions:

https://github.com/grwlf/urweb-etab/blob/master/Gregorian.ur

(1)(a) Where does the mkOrd function come from?

val ord_month = mkOrd { Lt = fn a b => monthToInt a < monthToInt b,
                        Le = fn a b => monthToInt a <= monthToInt b }

Idiom 5:

As deceptively simple as this may appear, it is truly epic:

https://github.com/grwlf/urweb-prelude/blob/master/src/Prelude.ur


(*

 _____            _           
|_   _|   _ _ __ | | ___  ___ 
  | || | | | '_ \| |/ _ \/ __|
  | || |_| | |_) | |  __/\__ \
  |_| \__,_| .__/|_|\___||___/
           |_|                
*)

fun fst [a:::Type] [b:::Type] ((x,_):(a*b)) : a = x

fun snd [a:::Type] [b:::Type] ((_,y):(a*b)) : b = y

It's very yin-hang or Hegelian in that it defines both:

constructing the product and deconstructing the projection

in a single phrase,

In some informal categorical sense it is a like a "one-line left adjunct" - similar to some informal categorical ideas from David Ellerman (a professor at Boston University):

http://www.ellerman.org/Davids-Stuff/Maths/Conc-Univ.pdf

Elsewhere at the end of in Etab.ur I see a similar elegant pairing of constructor/deconstructor (but now using records with uniquely named fields):

fun eventCity [t] [t~[City]] (e : record (t ++ [City = serialized city])) : city = deserialize e.City
fun eventKind [t] [t~[Kind]] (e : record (t ++ [Kind = serialized eventkind])) : eventkind = deserialize e.Kind
fun eventCountry [t] [t~[Country]] (e : record (t ++ [Country = serialized country])) : country = deserialize e.Country
fun eventLength [t] [t~[Start,Stop]] (e : record (t ++ [Start = time, Stop = time])) : int = daysDiff e.Start e.Stop
fun eventSport [t] [t~[Sport]] (e : record (t ++ [Sport = serialized sport])) : sport = deserialize e.Sport

This is very well-written and instructive.

Idiom 6: Type of error message defaults (of course!) to XML fragment

A naive programmer might ask "hmm, how do I return an error message, where do I return it, what type should it be, how do I get it up into that little box called a 'flash' on the next page?".

Now I see from your simple example that a wise programmer knows that any bit of UI (including an error message) is simply an XML fragment - to be spliced in later wherever needed.

fun head [a:::Type] (l:list a) : a = 
  case l of
    |[] => error <xml>head: empty list</xml>
    | x :: _ => x

fun strlist (s:string) : list char =
  let
    val l = strlen s
    fun strlist' s i =
      case i >= l of
        |True => []
        |False => ((strsub s 0) :: (strlist' (strsuffix s 1) (i+1)))
  in
    strlist' s 0
  end

Question:

In the function definitions:

https://github.com/grwlf/urweb-prelude/blob/master/src/Prelude.ur

fun insert  [a ::: Type] [b ::: Type] (_:eq a) (x:a) (y:b) (l : list (a*b)) : list (a*b) =
  (x,y) :: dropBy (fn (x',_) => x' = x) l

fun delete  [a ::: Type] [b ::: Type] (_:eq a) (x:a) (l : list (a*b)) : list (a*b) =
  dropBy (fn (x',_) => x' = x) l

What does this part mean?

(_:eq a)

Is this somehow saying that a is a type which is in typeclass Eq?

Is there some intuitive or informal sense to using a wildcard _ in this position?

I again see a wildcard _ in this position at the end of Prelude.ur, in functions show_pair and show_option:

val show_pair = fn [a ::: Type] [b ::: Type] (_ : show a) (_ : show b) => mkShow (fn ((x,y) : (a*b)) => "("^(show x) ^ "," ^ (show y) ^ ")")

val show_option = fn [a ::: Type] (_ : show a) => mkShow (fn (o:option a) => case o of |Some x => "Some (" ^ (show x) ^ ")" | None => "None")

It seems to be saying to me that:

fun id [t ::: Type] (x:t) : t = x

But it at least does seem to be saying that the following applications:

eq a
show a

do indeed return a valid type (regardless of whether populated or not), so this seems to be a declaration that type a is a member of typeclass Eq (resp. Show).

Idiom 7: ML data & SQL data

This is interesting to see the interaction between ML types and SQL records:

fun event_insert_ s e' : transaction int =
  let 
    val e : record event_details = e' ++ { Sport = serialize s }
  in
  i <- nextval events_gen;
  dml(INSERT INTO events(Id, Start, Stop, Caption, Country, City, Kind, Description, Sport)
      VALUES({[i]}, {[e.Start]}, {[e.Stop]}, {[e.Caption]}, {[e.Country]},
             {[e.City]}, {[e.Kind]}, {[e.Description]}, {[e.Sport]}));
  return i
  end

Conclusions and related Issues:

My experience is more in at algebraic data types and back-end (SQL) data modeling.

I am afraid of writing code involving events, timing, throttling / debouncing, interactivity - all the stuff involved in front-end development.

I imagine that these problems involve "co-algebraic process types" - the dual of my experience in algebraic data types.

It has has always been hard for me to understand the syntax and semantics of JavaScript (but easier to read things like CoffeeScript, Babel, ClojureScript, which use a more "functional" syntax.)

But now I think must force myself to learn enough front-end programming just to get the few data-bound UI widgets I need to put on the front-end of all databases:

I am still unsure if I should "wrap" an existing JavaScript library such as Mithril, as discussed here:

https://github.com/StefanScott/urweb-crudcrud/issues/4

You already provide libraries which wrap the more-standard, more-complete JavaScript library JQuery. So this means that one option would be for me to simply re-use your Ur/Web FFI code for JQuery. This would probably be easier in the beginning - after I to understand how to use your cake.

If I am using JQuery, then perhaps this means I could also use the sophisticated autocomplete widgets already developed which require JQuery:

I have been getting compiler errors doing this previously, described here:

https://github.com/StefanScott/urweb-crudcrud/issues/1 https://github.com/StefanScott/urweb-crudcrud/issues/2

But now I am thinking maybe I can use your Unsafe.s2xhead and Unsafe.s2xbody functions to solve this, by "splicing in" (inserting) the unsafe fragments which had been causing the compiler errors.

Question:

So, in some sense, the functions Unsafe.s2xhead and Unsafe.s2xbody are "splicing in" (inserting) arbitrary HTML fragments and avoiding scrutiny by the Ur/Web compiler?

Thank you for the code and examples you have provided!

PS - How are you surviving, doing this database work in Ur/Web, still with no UI autocomplete widget to let the user select a value for a foreign-key field??

sergei-mironov commented 9 years ago

Stefan, thank you for your positive review. It takes some time for me to prepare answers, I'll do it in a couple of days.

For now I answer to your very last question: in fact, I didn't write applications requiring complex interaction with users yet. Projects like etab or ecosrv (unfortunately, I will not maintain it any longer because I have changed the job) all use DB in a straightforward way. So your survey may be the first one in this area :)

StefanScott commented 9 years ago

Sergey -

Thank you again for providing these examples.

I understand that econat (and possibly etab) may be more a read-only db, with less user interaction (editing records).

I am interested in basic CRUD where there would be more editing by the users - so I am eager to get some kind of autocomplete widget to let the user easily select the foreign-key fields.

I understand you are busy so there is no need to respond quickly. I will also be busy doing other work, and there is plenty of excellent existing code you have written which I can continue studying.

On Mon, Jul 13, 2015 at 5:00 PM, Sergey Mironov notifications@github.com wrote:

Stefan, thank you for your positive review. It takes some time for me to prepare the answers, I'll do it in a couple of days.

For now I answer to your very last question: in fact, I didn't write applications requiring complex interaction with users yet. Projects like etab or ecosrv (unfortunately, I will not maintain it any longer because I have changed the job) all use DB in a straightforward way. So your survey may be the first one in this area :)

— Reply to this email directly or view it on GitHub https://github.com/grwlf/urweb-etab/issues/1#issuecomment-121038141.

sergei-mironov commented 9 years ago

Hi, Stefan, here is the longer answer from me:

SUMMARY:

Because you are actively programming in Ur/Web on practical projects, reading your code is very helpful for beginners like me to learn typical idioms and good style.

Perhaps you may someday also find some time to publish some annotations or commentaries to some of your code.

Although much of it may seem "obvious" to you - any commentaries regarding your code may be quite novel and instructive to beginner Ur/Web programmers such as myself.

I am really a beginner with Ur/Web - but I have studied functional languages such as ML and Haskell a lot.

The language I use mostly has been Maude - which is similar to ML and Haskell (differences: Maude has subtypes; it is first-level, not higher-level; and Maude's modules can contain axioms, unlike ML modules).

Thank you for sharing these contributions. I will continue to study them.

Well, I've been asking for nice idioms and your Etab.ur certainly has many nice idioms.

I am reading it more closely now and learning a lot :-)

https://github.com/grwlf/urweb-etab/blob/master/Etab.ur

I had of course repeatedly skimmed the grwlf/etab repository (apparently modeling archery competitions) 3-4 times in the past few months, expecting that (along with your other works ecosat and oil-price) I might be seeing some good examples there to learn from.

I had also looked a few times at your uru3 and urweb-soup and urweb-prelude.

I did not yet use them because I was afraid of possible additional complications due to the cake file - but perhaps I should learn to adapt to this as a necessity for building larger Ur/Web applications, as you have.

I have some initial basic questions:

(1) Your code uses a cake file, based on Haskell.

So I should first also install Haskell, in order to use Etab, correct?

Actually, no. You don't have to have Haskell to use Etab. cake3 is a Haskell tool which 'executes' Cake*hs files. The result of execution is Makefile, Makefile.dev and the whole folder of autogenerated modules. I keep those files in the repository so you can just make everything.

You need Haskell only if you want to join the development of urweb-etab. That is because cake3 is used to build the Ur/Web FFI wrappers and to embed binary files into the application.

By the way, did you notice that there are no lib.urp files in library folders? That is because lib.urp is a generated file too. The reason is that we don't alway know the linker flags since they may depend on end-user system (it is pkg-config's job to find them). So if we speak about library project like urweb-soup, than you shoud execute make lib in order to build lib.urp. After that, you may use the library as usual (I repeat, no Haskell is needed for building).

(from time to time I forget to add something important for building the repo, it should be considered as a bug))

(2) The purpose of this function:

https://github.com/grwlf/urweb-soup/blob/dcd4131a5cf2b51154c4c432fd8c263c1175f4fa/Unsafe.urs

Is to allow the programmer to include arbitrary HTML fragments in the HTML output from the Ur/Web compiler, correct?

These s2xhead and s2xbody functions were contributed by you then?

Yes, it was me who wrote them. I use them to embed third-party snippets like google Analytics code. Such snippets usually has to be inserted as-is, re-writing their logic in Ur/Web is IMHO a bad way.

I was expecting that s2xhead and s2xbody would specify the concrete location to "splice in" the resulting HTML fragments - but now I see that it these functions merely do some kind of "wrapping".

Now I see that the specification of the location where to "splice in" the fragment of course simply occurs at the particular location of insertion of value 'donate' (which calls Unsafe.s2xbody), towards the end, here:

        </ul>
        {donate}
        </p>
      </xml>

I think that Ur/Web type system can't be used to hardly restrict the location of a snippet. It allows us to say something like "don't insert this thing into

" but it is impossible to specify more concrete location.

Some other interesting idioms I am noticing:

Idiom 1: Blessing a directory.

I didn't know you could just do this, and assign the result to a value.

But of course this makes sense now: bless isn't some exceptional syntax, it is merely a function call, and returns a useful value.

val srcprj = bless "https://github.com/grwlf/urweb-etab"

I believe, Ur/Web thinks about urls as about strings and matches them by using some kind of regular expression.

Idiom 2: It is interesting that you aren't even use an SQL database at all. Just using native ML-style data types.

This is fascinating and encouraging to me.

UPDATE: Ah I see later you do use an SQL database - and you have interesting DML code to interface between the ML-style datatypes, and the SQL.

Yes, I use the database, since Etab will offer some statefulness to its users: I plan to allow users to add the events to the calendar. ML-style datatypes may be serialized/deserialized into the database (it is interesting to look in the database and see how they are represented there). I am not sure if it is possible to refer to this fields in SQL queries. Probably, no, since database stores serialized ML-datatypes as Text fields, loosing its type.

Idiom 3:

fun template_ w links mb : transaction page =
  let
  Uru.run (
  JQuery.add (
  Bootstrap.add (
  Soup.layout {Width=w} (fn nar =>
  Uru.withStylesheet (Etab_css.url) (
  Uru.withHeader

As mentioned above, I had looked at the uru3 repository a few times in the past months. I guess I got intimidated by the cake file, and wanted to avoid using any extra layers in my initial, minimal (ie, "Hello World") attempts to implement some sort of autocomplete widget in Ur/Web.

Now I also recall that any cake file is simply necessary 'glue' code to put files together at the OS level, and I see that the cake dialect being used is Haskell (not C), so I understand that I should just have my cake and eat it too.

Probably, yes, but I repeat, it is not necessary to do the cake business if you want to use, say, Uru library. You may just clone Uru repository, do the make lib and then specify something like library urweb-uru3 in your HelloWorld.urp. This should be enough to call Uru.run and friends

Questions regarding cake:

It seems that cake3 is your invention, correct?

Yes, actually it was intended to be the Makefile generator for embedded projects, but it turns out that I use to primarily for Ur/Web development.

I will have to install Haskell to use it, correct?

Yes, but only if you want to join the development of a library which uses it. It is not required for building since Makefile it produces is (should be) already in the repo.

(I have installed Haskell a few times in the past, but now I am on a new Debian machine with almost nothing - only Ur/Web. I imagine it is now time to install Haskell too.)

Idiom 4: This is interesting, suggesting that the most important thing to capture or know (ie parameterize) about any Layout is its width.

Soup.layout {Width=w}

Aha. Here is the example of third-party library (urweb-soup in this case) which uses Uru. It defines some Bootstrap template I often use

Questions:

https://github.com/grwlf/urweb-etab/blob/master/Gregorian.ur

(1)(a) Where does the mkOrd function come from?

val ord_month = mkOrd { Lt = fn a b => monthToInt a < monthToInt b,
                        Le = fn a b => monthToInt a <= monthToInt b }

It comes from the basis.urs library. You may find it in the Ur/Web repo, lib/ur/basis.urs.

Idiom 5:

As deceptively simple as this may appear, it is truly epic:

https://github.com/grwlf/urweb-prelude/blob/master/src/Prelude.ur


(*

 _____            _           
|_   _|   _ _ __ | | ___  ___ 
  | || | | | '_ \| |/ _ \/ __|
  | || |_| | |_) | |  __/\__ \
  |_| \__,_| .__/|_|\___||___/
           |_|                
*)

fun fst [a:::Type] [b:::Type] ((x,_):(a*b)) : a = x

fun snd [a:::Type] [b:::Type] ((_,y):(a*b)) : b = y

It is not strange that Adam did not define them. Ur/Web has a syntax to access tuples elements. If I remember correctly, it is typle-dot-number

(The big bunner is created with the 'figlet` utility)


It's very yin-hang or Hegelian in that it defines both:

constructing the product and deconstructing the projection

in a single phrase,

In some informal categorical sense it is a like a "one-line left adjunct" - similar to some informal categorical ideas from David Ellerman (a professor at Boston University):

http://www.ellerman.org/Davids-Stuff/Maths/Conc-Univ.pdf

Category theory is my weak point. COuld you recomend some not-too-hard book about it? I once tried to learn it from YouTube lectures, but Lecture 2 had almost killed me.

Elsewhere at the end of in Etab.ur I see a similar elegant pairing of constructor/deconstructor (but now using records with uniquely named fields):

fun eventCity [t] [t~[City]] (e : record (t ++ [City = serialized city])) : city = deserialize e.City
fun eventKind [t] [t~[Kind]] (e : record (t ++ [Kind = serialized eventkind])) : eventkind = deserialize e.Kind
fun eventCountry [t] [t~[Country]] (e : record (t ++ [Country = serialized country])) : country = deserialize e.Country
fun eventLength [t] [t~[Start,Stop]] (e : record (t ++ [Start = time, Stop = time])) : int = daysDiff e.Start e.Stop
fun eventSport [t] [t~[Sport]] (e : record (t ++ [Sport = serialized sport])) : sport = deserialize e.Sport

This is very well-written and instructive.

Idiom 6: Type of error message defaults (of course!) to XML fragment

A naive programmer might ask "hmm, how do I return an error message, where do I return it, what type should it be, how do I get it up into that little box called a 'flash' on the next page?".

Now I see from your simple example that a wise programmer knows that any bit of UI (including an error message) is simply an XML fragment - to be spliced in later wherever needed.

fun head [a:::Type] (l:list a) : a = 
  case l of
    |[] => error <xml>head: empty list</xml>
    | x :: _ => x

fun strlist (s:string) : list char =
  let
    val l = strlen s
    fun strlist' s i =
      case i >= l of
        |True => []
        |False => ((strsub s 0) :: (strlist' (strsuffix s 1) (i+1)))
  in
    strlist' s 0
  end

Actually, I think it is bad example of good style :) In reality, the error fragment may not be spliced anywhere. The built-in Basis.error function terminates the page generation and displays the ugly 'Internal server error' page.

Question:

In the function definitions:

https://github.com/grwlf/urweb-prelude/blob/master/src/Prelude.ur

fun insert  [a ::: Type] [b ::: Type] (_:eq a) (x:a) (y:b) (l : list (a*b)) : list (a*b) =
  (x,y) :: dropBy (fn (x',_) => x' = x) l

fun delete  [a ::: Type] [b ::: Type] (_:eq a) (x:a) (l : list (a*b)) : list (a*b) =
  dropBy (fn (x',_) => x' = x) l

What does this part mean?

(_:eq a)

Is this somehow saying that a is a type which is in typeclass Eq?

Is there some intuitive or informal sense to using a wildcard \_ in this position?

I again see a wildcard _ in this position at the end of Prelude.ur, in functions show\_pair and show\_option:

val show_pair = fn [a ::: Type] [b ::: Type] (_ : show a) (_ : show b) => mkShow (fn ((x,y) : (a*b)) => "("^(show x) ^ "," ^ (show y) ^ ")")

val show_option = fn [a ::: Type] (_ : show a) => mkShow (fn (o:option a) => case o of |Some x => "Some (" ^ (show x) ^ ")" | None => "None")

It seems to be saying to me that:

  • There is some function which returns a value of type eq a, or of type show a.
  • I wonder if this asserted ("initial"?) function would necessarily be:
fun id [t ::: Type] (x:t) : t = x
  • I imagine that this phrase doesn't say whether the range of the function \_ is populated or not.

But it at least does seem to be saying that the following applications:

eq a
show a

do indeed return a valid type (regardless of whether populated or not), so this seems to be a declaration that type a is a member of typeclass Eq (resp. Show).

Yes, it is the Ur/Web way of specifying type classes.

fun insert  [a] [b] (_:eq a) (x:a) : (a*a) = ...

is equal to Haskell's

insert :: Eq a => a -> (a,a)
insert x = ...

Idiom 7: ML data & SQL data

This is interesting to see the interaction between ML types and SQL records:

fun event_insert_ s e' : transaction int =
  let 
    val e : record event_details = e' ++ { Sport = serialize s }
  in
  i <- nextval events_gen;
  dml(INSERT INTO events(Id, Start, Stop, Caption, Country, City, Kind, Description, Sport)
      VALUES({[i]}, {[e.Start]}, {[e.Stop]}, {[e.Caption]}, {[e.Country]},
             {[e.City]}, {[e.Kind]}, {[e.Description]}, {[e.Sport]}));
  return i
  end

Conclusions and related Issues:

My experience is more in at algebraic data types and back-end (SQL) data modeling.

I am afraid of writing code involving events, timing, throttling / debouncing, interactivity - all the stuff involved in front-end development.

I imagine that these problems involve "co-algebraic process types" - the dual of my experience in algebraic data types.

It has has always been hard for me to understand the syntax and semantics of JavaScript (but easier to read things like CoffeeScript, Babel, ClojureScript, which use a more "functional" syntax.)

But now I think must force myself to learn enough front-end programming just to get the few data-bound UI widgets I need to put on the front-end of all databases:

  • autocomplete widget
  • datagrid
  • master-detail form layout (a "parent" datagrid linked to a "child" datagrid, via an SQL foreign key)

I am still unsure if I should "wrap" an existing JavaScript library such as Mithril, as discussed here:

https://github.com/StefanScott/urweb-crudcrud/issues/4

You already provide libraries which wrap the more-standard, more-complete JavaScript library JQuery. So this means that one option would be for me to simply re-use your Ur/Web FFI code for JQuery. This would probably be easier in the beginning - after I to understand how to use your cake.

If I am using JQuery, then perhaps this means I could also use the sophisticated autocomplete widgets already developed which require JQuery:

  • twitter typeahead.js
  • Select2

I have been getting compiler errors doing this previously, described here:

https://github.com/StefanScott/urweb-crudcrud/issues/1 https://github.com/StefanScott/urweb-crudcrud/issues/2

But now I am thinking maybe I can use your Unsafe.s2xhead and Unsafe.s2xbody functions to solve this, by "splicing in" (inserting) the unsafe fragments which had been causing the compiler errors.

Question:

So, in some sense, the functions Unsafe.s2xhead and Unsafe.s2xbody are "splicing in" (inserting) arbitrary HTML fragments and avoiding scrutiny by the Ur/Web compiler?

Technically, yes. s2xbody and s2xhead are able to insert aritrary strings into final XML result. But IMHO you shouldn't use them for complex code. I use them only to insert Analytics or 'DonateButton' third-party code.

Also note, that I didn't wrap JQuery in Ur/Web. Uru/JQuery's most important function is JQuery.add which does no more than adding needed by other third-party libraries.

JQuery is damn big, so wrap it completely is hardly possible for me. More, I don't need every JQuery function to be wrapped.

That is why I wrap only very end-user libraries I need. Let me demonstrate it for the case of DialogPolyfill. DialogPolyfill is a javaScript library for working with modal dialogs. It requires JQuery in order to work correctly. See the uru3/Dialog folder. Here is what I do to wrap it:

You may try to find your way for wrapping Autocmplete and others. Try to wrap them in simplest possible JavaScript first! The JavaScript should be simple enough for Ur/Web JS-FFI syntax. After that, write this FFI *urs. Then you will see how it goes and decide what to do next.