• Modules
    • By category
    • By name
    • Most popular
    • Most downloaded
    • Repository
  • Register
  • Log in
  • Help
    • Start using Ceylon Herd
    • Publish your first module
    • Module publishing guidelines
    • All about Ceylon
    • Keyboard Shortcuts

    • s Focus search module bar
      ? Open this information panel
      j Move selection down
      k Move selection up
      enter Open current selection
Module info
Name
FroMage / ceylon.html / 1.2.2
Ceylon HTML Platform Module
Category SDK

The Ceylon SDK

Backends JVM JavaScript
Maven coordinates
Compatible Ceylon release JVM: 1.2.x, 1.3.x (latest)
JavaScript: 1.2.1, 1.2.2, 1.3.x (latest)
Published Mar 11, 2016
Stats Downloads (JVM): 801
Downloads (JS): 143
Source downloads: 607
Authors Daniel Rochetti
John Vasileff
Tomáš Hradec
Description

The ceylon.html module contains HTML5 templating engine:

  • with an elegant and type safe way of creating templates
  • witch works on both platforms, server (jvm) and client (js)
  • based on named argument invocations syntax
  • supporting reusability of snippets and lazy evaluation

CONTENT

  1. What does it look like?
  2. Basic usage
  3. Iteration
  4. Conditions
  5. Lazy evaluation
  6. Reusable blocks and layouts

<a name="what"></a> WHAT DOES IT LOOK LIKE?

A quick preview shows code example, which starts HTTP server, see module ceylon.net, and on each request returns simple HTML5 document with obligatory greeting. Note that the module is not tied with any web framework, it can be used anywhere.

value server = newServer {
    Endpoint {
        path = startsWith("/");
        service = (req, res) {
            renderTemplate(
                Html {
                    Body {
                        H1 { "Hello `` req.queryParameter("name") else "World" `` !" }
                    }
                },
                res.writeString);
        };
    }
};
server.start();

<a name="basic"></a> BASIC USAGE

The module contains HTML elements, which can be composed together into template. The element has attributes and content (usually other elements or text data). Each element can belong to predefined content category (eg. flow, phrasing, metadata, …). Those categories are then used to specifying permitted element's children. During rendering of template is applied automatic escaping of all potentially unsafe data.

Let's look on more complicated example, below is template with login form and with a preview of generated HTML in the second half.

<table style='width:100%'> <tr style='vertical-align: top'>

  <td style='width:50%'>

<pre data-language='ceylon'> Html {

Head {
    Title { "Login" },
    Link { href = "/resources/style.css"; rel = "stylesheet"; }
},
Body {
    Form { clazz = "login-form"; autocomplete = true;
        H1 { "Login" },
        Label { "Name", 
            Input { id = "name"; type = InputType.text; } 
        },
        Label { "Password",
            Input { id = "pswd"; type = InputType.password; }
        },
        Button { type = ButtonType.submit; "Sign in" }
    }
}

} </pre>

  </td>
  <td>

<pre data-language='html'>

<!DOCTYPE html> <html>

<head>
    <title>Login</title>
    <link href="/resources/style.css" rel="stylesheet">
</head>
<body>
    <form class="login-form" autocomplete="on">
        <h1>Login</h1>
        <label>Name
            <input id="name" type="text">
        </label>
        <label>Password
            <input id="pswd" type="password">
        </label>
        <button type="submit">Sign in</button>
    </form>
</body>

</html>

</pre>

  </td>         

</tr> </table>


<a name="iteration"></a> ITERATION

A comprehension comes handy for iterating over several items and applying filtering and transformation. For example, this snippet use comprehension for transforming list of super-heroes into table rows, with three cells.

<table style='width:100%'> <tr style='vertical-align: top'>

  <td style='width:50%'>

<pre data-language='ceylon'> Table {

for(i->superhero in superheroes.indexed)
    Tr {
        Td { "#``i``" },
        Td { superhero.nickname },
        Td { superhero.powers }
    }

}; </pre>

  </td>
  <td>

<pre data-language='html'> <table>

<tr>
    <td>#1</td>
    <td>Wolverine</td>
    <td>regeneration</td>
</tr>
<tr>
    <td>#2</td>
    <td>Dr. Manhattan</td>
    <td>subatomic manipulation</td>
</tr>
...

</table> </pre>

  </td>         

</tr> </table>

Alternatively it is possible to use full power of streams API. For example, this snippet contains names of top ten bad guys and use sorting, filtering and final transformation into list element.

<table style='width:100%'> <tr style='vertical-align: top'>

  <td style='width:50%'>

<pre data-language='ceylon'> Ul {

badGuys.sort(decreasing).take(10).map((badGuy) =>
    Li { badGuy.name })

}; </pre>

  </td>
  <td>

<pre data-language='html'> <ul>

<li>Ultron</li>
<li>Red Skull</li>
<li>Green Goblin</li>
...

</ul> </pre>

  </td>         

</tr> </table>


<a name="conditions"></a> CONDITIONS

Sometimes a fragment of template or attribute value depends on a certain conditions. In that cases is possible to use then/else operator

Div {
    user.isAdmin then Button { "Delete" }
}

or if expression

Div {
    if (exists user, user.isAdmin) then
        Button { "Delete" }
    else
        Span { "No permission" }
}

or switch expression

Span {
    switch (n)
        case (0) "zero"
        case (1) "one"
        else "many"
}

<a name="lazy"></a> LAZY EVALUATION

One possible supported scenarios is lazy evaluation of templates, which allows to create template once, hold its instance, but render it each time with actual data.

This is automatically supported with usage of comprehensions (where elements of resulting iterable are evaluated lazily) or with usage of lazy operations over streams (eg. map method produce lazy view).
In the example, the output of print function, for the first time (1), will be list with two items, but list with four items in the second evaluation (2).

value todoList = ArrayList<String>();
todoList.add("wake up");
todoList.add("make coffe");

value todoSnippet = Ul {
    for(todo in todoList)
        Li { todo } 
};
print(todoSnippet); // 1.

todoList.add("drink coffe")
todoList.add("make more coffe")

print(todoSnippet); // 2.

Another option is to pass no-arg function, returning desired value, instead of value itself. For example this div element, will be hidden, depending on user configuration.

Div { 
    id = "preview"; 
    hidden = () => !userConfig.showPreview;
    ...
}

<a name="layout"></a> REUSABLE BLOCKS and LAYOUTS

Template fragments can be super-easily encapsulated and reused, which safes our fingers and increase readability. If needed, they can be naturally parameterized. Compare this example, form with several input fields and its counterpart.

<table style='width:100%'> <tr style='vertical-align: top'>

  <td style='width:50%'>

<pre data-language='ceylon' style='margin-bottom:2px'> value form = Form {

input("firstname", "First name"),
input("lastname", "Last name"),
input("phone", "Phone", InputType.phone),
input("email", "E-mail", InputType.email)

}; </pre>

<pre data-language='ceylon'> Div input(String id, String label, InputType type=InputType.text) =>

Div { clazz="form-group";
    Label { forElement = id; label },
    Input { id = id; clazz="form-control"; type=type; }
};

</pre>

  </td>
  <td>

<pre data-language='html'> <form>

<div class="form-group">
    <label for="firstname">First name</label>
    <input id="firstname" class="form-control" type="text">
</div>
<div class="form-group">
    <label for="lastname">Last name</label>
    <input id="lastname" class="form-control" type="text">
</div>
<div class="form-group">
    <label for="phone">Phone</label>
    <input id="phone" class="form-control" type="tel">
</div>
<div class="form-group">
    <label for="email">E-mail</label>
    <input id="email" class="form-control" type="email">
</div>

</form>
</pre>

  </td>         

</tr>

</table>

This can be easily used as mechanism for defining common layout for all pages in web application, as sketched in following example.

Html myHtml(Content<FlowCategory> content) =>
    Html {
        Head {
            Title { "MyApp" },
            Meta { charset="utf-8"; },
            Link { href = "/resources/style.css"; rel = "stylesheet"; }
        },
        Body {
            Div { clazz="content";
                content
            },
            Div { clazz="footer";
                "All Rights Reserved."
            }
        }
    };

Then the page is created as…

myHtml({
    H1 { "Welcome in MyApp!" },
    Div {
        ...    
    }
})   

Dependencies
ceylon.collection/1.2.2
ceylon.language/1.2.2
Usage
  • Import
 import ceylon.html "1.2.2";
Module links Members
Imported By
Home
Code repository
Issue tracker
Browse
Download .car
Download .js
Download source archive
Download module documentation
View API documentation

Ceylon Herd v1.24 Copyright 2012-2023 Red Hat. About