Name |
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
CONTENT
<a name="what"></a> WHAT DOES IT LOOK LIKE?A quick preview shows code example, which starts HTTP server, see module 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 USAGEThe 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> ITERATIONA 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> CONDITIONSSometimes 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 EVALUATIONOne 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). 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 LAYOUTSTemplate 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> </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 | |
Usage |
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 |