Git Product home page Git Product logo

purescript-smolder's Introduction

Low Maintenance Warning

This library is in low maintenance mode, which means the author is currently only responding to pull requests and breaking compiler updates. If you want to take over maintainership of this library, please feel free to open an issue about it.

purescript-smolder

A simple combinator library for generating HTML in PureScript, heavily inspired by Haskell's BlazeHtml.

Usage

Write HTML elements as functions, with the ! combinator to add attributes, and do notation to add child elements:

doc = html ! lang "en" $ do
  h1 $ text "My HTML Document"
  p $ do
    text "This is my HTML document. It is "
    em $ text "very"
    text " nice. "
    a ! href "more.html" $ text "There is more."

You can render lists of items inside the do notation using traverse_ or for_:

import Data.Foldable (for_, traverse_)

items = ["fear", "surprise", "ruthless efficiency"]

item i = li $ text i

bulletList = ul $ do
  for_ items item
  -- or traverse_ item items

(Note that the Data.Foldable versions of traverse_ and for_ can blow the stack if you have a lot of items (just short of 10k items will do it), but because Markup has a MonadRec instance, you can use the implementations from purescript-safely if you're worried about this.)

Use the #! combinator to attach event handlers:

import Effect.Class.Console (log)

doc = div ! className "not-a-form" $ do
  button #! on "click" (\event → log "boom!") $ text "boom"

You can render the markup to a string:

import Text.Smolder.Renderer.String (render)

doc = html ! lang "en" $ do
  body $ do
    h1 $ text "Hello Joe"

docAsString = render doc
-- "<html lang=\"en\"><body><h1>Hello Joe</h1></body></html>"

There are other renderers available, such as a renderer for DOM nodes.

Types

The type of the markup is Markup e, where the e is the type of the event handler, which is only important when you want to render your markup. For rendering to the DOM, this would have to be EventListener (dom :: DOM | eff). The string renderer accepts any type for e, as it ignores event handlers altogether.

Markup e is a type alias for Free (MarkupM e) Unit, a free monad over markup nodes, but you don't need to worry about free monads at all. Unless you're writing your own renderer, you should just use Markup e in your own code.

Licence

Copyright 2015 Bodil Stokke

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see http://www.gnu.org/licenses/.

purescript-smolder's People

Contributors

bodil avatar coot avatar drewolson avatar euregan avatar gabysbrain avatar hgiasac avatar justinwoo avatar matthewleon avatar mjhoy avatar paf31 avatar paluh avatar roryc89 avatar sharkdp avatar unisay avatar zyla avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

purescript-smolder's Issues

virtual-dom renderer?

I know this got removed but are there any plans to create a package with the old code?

Rendering a large number of elements exceeds maximum call stack size

Hi Bodil,

Thank you for your effort in putting together this library — I’ve been using it happily in a few projects.

I have come across an error in which rendering a large number of elements to the page will exceed Javascript’s maximum call stack size. The code in question relies on traverse_ to render several thousand rows of a table.

About The Error

The error in question:

Uncaught RangeError: Maximum call stack size exceeded
    at Monad.Applicative0 (bundle.js:24516)

...

// bundle.js 24516
var monadMarkupM = new Control_Monad.Monad(function () {
      return applicativeMarkupM;
  }, function () {
      return bindMarkupM;
  });

@justinwoo helped me realize that by default monadic code isn’t tail recursive; if I need it to be, I need to use a traversal that implements MonadRec from purescript-tailrec. If the monad implements MonadRec, I can use purescript-safely or write my own tail-recursive function and all is well.

However, MarkupM doesn’t have an instance of MonadRec. In a discussion with @natefaubion, he had suggested there may not be a possible instance of MonadRec for this monad.

Finally, I am relying on purescript-pux, which itself relies on Smolder for its HTML. At the moment, I am not aware of a way to use another HTML library with Pux.

Reproduction

I’ve created a GitHub repo that implements a simple demonstration of this, and which should be easily cloned / run if you’d like to take a look at the error and the code that causes it directly.

https://github.com/saylu/purescript-framework-benchmark

Next Steps

With all of this said, the main questions I am looking to answer are:

  1. Is there a way to handle this case effectively in Smolder?
  2. If not, is there a possible workaround so that it is possible to render a large number of items, even if it is slow?

Wishing you the best,
Thomas

Add LICENSE file

Looking at bower.json, it looks like this is LGPL3. Is that right?

I'm using this for purescript-rest, and I'd like to reference the license properly.

URI-encoding hrefs seems unexpected

The fact that

render $ a ! href "some%20string" $ text "inner"

produces

<a href="some%2520string">Inner</a>

rather than

<a href="some%20string">Inner</a>

Seems a bit unexpected. I ran into an issue with using Pux, as the react renderer won't encodeURI href props, but attempting to render the same markup to a string caused this double encoding issue.

Is this expected behavior?

(Related: #31)

Question: Make Markup a monad?

Would you entertain a pull request which made Markup into a law-abiding monad? I would probably use the approach from the DSL chapter of the book.

I appreciate you might like to keep this approach for performance reasons, so I wanted to ask before starting to write code ...

Renderer generates invalid self-closing tags

<ul /> is invalid HTML 5 for example, but will be generated by H.ul $ mempty. For HTML which is generated programmatically, this can be an issue.

Maybe each element needs to track whether it can be self-closing or not?

Make fromStream tail recursive

With large inputs, fromStream in Text.Smolder.Renderer.String can exceed maximum call stack. In our project, we have experienced this with a textarea containing text with 11302 characters and 152 lines. To prevent this, tail recursion can be added to fromStream.

First-class comments in Markup

I define comment as follows, but this is obviously premature rendering and depends on text not escaping its string (which I think it should).

comment :: Markup -> Markup
comment m = text $ "<!--" <> render m <> "-->"

It would be nice to offer first-class commenting support out of the box.

Maintainers?

Are there already some other maintainers of this package? Otherwise I could be one, just to release new versions of this package compatible with newer PureScript releases. e.g. #47

Usage with DOM Renderer

First of all, thank you for all your hard work! Without you, the purescript package library would be woefully tiny.

I have a question about the correct way to use purescript-smolder with the DOM renderer.

In the README for this repository, this example is provided for adding a click listener to a button:

doc = div ! className "not-a-form" $ do
  button #! on "click" (\event → log "boom!") $ text "boom"

When I check the type of this in the REPL, it resolves to:

forall t11 t12.                     
  MarkupM                           
    (t11                            
     -> Eff                         
          ( console :: CONSOLE      
          | t12                     
          )                         
          Unit                      
    )                               
    Unit

The type for render is render :: forall eff. Element -> Markup (E eff) -> Eff (dom :: DOM | eff) Unit, so when I go to render like this: render wrapper doc (where "wrapper" is an Element), I get this compiler error:

  Could not match type

    Function t1

  with type

    EventListener


while trying to match type t1
                           -> Eff
                                ( console :: CONSOLE
                                | t2
                                )
                                Unit
  with type EventListener
              ( dom :: DOM
              | t0
              )
while checking that expression doc
  has type MarkupM
             (EventListener
                ( dom :: DOM
                | t0
                )
             )
             Unit
in value declaration renderControls

where t0 is an unknown type
      t2 is an unknown type
      t1 is an unknown type

And I'm positively stumped. I'm still pretty new to purescript so reading an error like this is very difficult for me. I'm sorry to submit an issue here since I'm probably doing something wrong, but I didn't know where else to get help.

Thanks!

Leverage purescript-virtual-dom from contrib

It would be useful for smolder to use the virtual dom package purescript-virtual-dom in purescript-contrib instead of rolling its own bindings. This would, for instance, standardized the VTree type across the libraries, and possibly other functionality.

See comment from @garyb here regarding smolder and virtual-dom.

question - am I doing it wrong?

I have this:

indexDoc = html ! lang "en" $ do
  head $ do
    meta ! charset "utf-8"
    meta ! httpEquiv "X-UA-Compatible" ! content "IE=edge,chrome=1"
    script ! src "/js/game.js" ! defer ""
    style $ text "a bunch of css here"
  body $ do
    div $ do
      canvas ! id "foreground"
      canvas ! id "background"

But it fails with "Cannot unify Text.Smolder.Markup.MarkupM with Prim.Function (Text.Smolder.Markup.MarkupM Prelude.Unit)." on the line style $ text "a bunch of css here" at column 5. Do you know how to fix this?

Insert raw html string

I have a raw html string coming from an external source, which I would like to insert into a Smolder Markup template. If I use the text function, the html gets escaped. I need to insert it as a raw string without escaping. Is this possible and how?

Support name generation

Now that MarkupM is a free monad, we can support things like

view = do
  top <- freshName
  a ! name top $ mempty
  ...
  a ! anchor top $ text "Back to top"

  where
  anchor name = href $ "#" <> runName name

Use purescript-free and purescript-inject?

Would you take a PR to change the MarkupM monad to use purescript-free?

I would also like to be able to use purescript-inject to make the various HTML element smart constructors work with different free monads, so that we can extend the DSL in libraries.

I appreciate if that's not the goal of the library though, so I wanted to ask before starting to work on anything.

type' attribute is escaping "/"

If I add script ! type "application/sjon" $ text "" this is rendered (to string) as
<script type="application&#x2F;json></script>. It seems that all attributes are escaped href to which makes it useless.

The type of String could be substituted wtih Either String String with Left being unsafe (not escaped) and Right safe string (escaped when processes).

Directions for data attributes?

Hello, i want to use data attributes with Smolder, which means attributes that are not provided by the library, by definition. Could you point me to some resources about how to do that? Thanks in advance

SVG generation

Would it be ideologically right to have a HTML5.SVG module to emit svg tags?

Interest in a pretty printer?

I notice that the string renderer encodes markup into a very compact string. Would you have any interest in an encoder that does your typical pretty printing: probably accepting a set of options for indentation? I'm happy to do the work on this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.