rp-widget
Templates for rp. WORK IN PROGRESS!
They initially render to HTML and than update to DOM when anything changed.
Usage
Compile:
rp-widget template.rpw
Use with some CommonJs runtime:
// choose a runtime before requiring templatesvar rpWidget = ;// require the compiled templatevar template = ;// The rp libraryvar rp = ;var data = rp;var param1 = rp;var param2 = rp;rp;
RPW
Syntax for Just write normal HTML with some extra stuff.
Inline{{= data.a.b.c }} Renders a text{{{= data["xyz"].b }}} Renders a html (unsafe!!){{ data("p")() + data("v")() }} Renders a computed value as text{{{ data("p")() + data("v")() }}} Renders a computed value as html (unsafe!!)As attributes<input value="Text" disabled=true /> Const as normal<input checked=data.a.b.c /> Bind references<span style={{ "background: " + color() }}> Bind computed values </span><span checked={{{ which() ? color : data("color") }}}> Bind delegated values </span><div class="one" class="two"> Multiple values are joined with space </div>
Arguments and Variables
<#arg data default> Give the main argument a name<#arg param1> Additional arguments (required, will throw if missing)<#arg param3 default=null> Additional arguments with default value (optional)<#var items={{ [1,2,3] }}> Define a local variable (rp.variable) with initial value<#var bool=true><#let temp={{{ items.size() }}}> Store temporary RP with <#let><#let temp2= items filter {{ _%2==0 }} reduce {{ a+b }} plus 1> With operations
Partials
A partial is used like a HTML element but starting with a upper case letter.
They get a main argument plus multiple arguments as attributes.
The content is the main partial given the the called partial. Other partials can given by <#name> and can take an argument.
You can name the main argument given to your provided partial with "as" plus identifier
<Partial "main argument" param1=additional.argument param2=123.456>The Partials main partial<#xyz>In first additional partial<#abc "main argument to partial">In second additional partial</Partial>
Example: The included "If" and "ForEach" partials:
<ul><ForEach items as item><li><If item.done><span>Item {{= item.text }} is done.</span><#elseif {{ item("text")().length > 0 }}><span>{{= item.text }} need to be done.</span><#else><span style="background: red">Empty item</span></If></li></ForEach></ul>
Because some stuff is reactive it need to be wrapped in a html element.
Not allowed if x is not constant:<div>Text<If x>abc</If></div>Allowed:<div>Text<span><If x>abc</If></span></div>
The wrapping element (<span>
) gets a special class to identify the element and exchange the html content if x is changed.
Using provided partials
The main partial can be used a "Partial": <Partial /><#partial as Name> Give the main partial another name (instead of Partial)<#partial type as Name> Get the additional partial <#type> (throws if missing or multiple)And use it: <Name /><#partial type as Name optional> (doesn't throw if missing, but is null)<#partial type as Name default=OtherName> Defaults to another partial<#partial type as Name with value> Get the <#type> partial and the value (throws if missing or multiple)<#partials type as array><#partials type as array> Get all matching partials as array of {p: Partial, v: RP} (RP)<ForEach array as element><#let value = element.v delegated><#let partial = element.p><*{{=partial}} value /></ForEach>
Prefix
Attributes of HTML elements can have a prefix, which describe the way they are handled.
<input attr:value=xyz />Bind xyz to the attribute "value"Changed of "value" are not propagated to xyz<input property:indeterminate=xyz />The "property" prefix bind xyz to the propertyinstead of the attribute<input bpc:value=xyz />The "bpc" prefix bind xyz to the attribute valueand the property value tobpc: "Bind Property Change"bpku: "Bind Property Key Up"bpkd: "Bind Property Key Down"bpkp: "Bind Property Key Press"bpi: "Bind Property Input"<button on:click=someFn />The "on" prefix just bind a eventThe argument should be a RP resolving to a}}} /><div style:height="50px" class:my-class=true class:other-class=x></div>Shortcuts for style and class
There are some useful defaults if you don't set the prefix. I. e. "value" defaults to "bpc:value".
id
attribute
Use the id attribute on html elements. They are bound to variables. You can access them in your code.
Example:
<button id="myButton" on:click={{{myButton === this; // Depends on runtime...myButton.disabled = true;}}}>Button</button>
But better do it this way:
<#var buttonDisabled=false><button disabled=buttonDisabled on:click={{{buttonDisabled.set(true);}}}>Button</button>
<script>
Custom code...
<script> __buf; </script>Run when generating html<script load></script>Run at end of atomic The HTML is now in the DOM<script changed dataabc></script>Handle event of RPs<script private ></script>Define a local></script>Define a exported function, which can be used from outside too.You need to instanciate the widgets with a "id" property.<Xyz id="abc" /> <script> abc.myFunction(1,2); </script><script dispose>clearTimeout(t)</script>Run when widget is no longer needed.
Use with webpack
With webpack you don't need to compile your template. It will do it for you. Just configure the loader and the extension with:
moduleexports =module:loaders:test: /\.rpw$/ loader: "rp-widget"resolve:extensions: "" ".webpack.js" ".web.js" ".rpw" ".js"
And require the template with require("./template")
.
FAQ
Why another templating language?
It's not just a templating language, it's reactive template. The DOM will ever reflect the current value of the data. But it looks like a templating language, to atract users and be simple to use.
Why not in Jade style?
rp-widget is modular (parser -AST-> (optimizer) -AST-> generator). So it possible (and planed) to make a jade style parser too.
What is the difference to React?
- React can have templates inlined in javascript. rp-widget cannot do this.
- React rerenders templates and compute the difference. rp-widget only renders and updates changed elements.
- React and rp-widget are both declarative. React has one-way bindings, rp-widget two-way bindings.
Hello World
/** @jsx React.DOM */var HelloMessage = React;
<#arg name>Hello {{= name }}
TODO App
/** @jsx React.DOM */var TodoList = React;var TodoApp = React;
<#define TodoList><#arg items>{{= item }}<#var items = {{ [] }}><#var text = "">TODO<#let nextNum = items size plus 1>Add #{{= nextNum }}
TODO
- More included Widgets
- parse basic expressions in attributes
<a href="xyz"+data.x>
- remove whitespace when appropriate
- optimize the resulting AST
License
MIT