Namdak Tonpa 9 years ago
commit
31988bb291
94 changed files with 3157 additions and 0 deletions
  1. 18 0
      LICENSE
  2. 16 0
      README.md
  3. 190 0
      include/nitro.hrl
  4. 6 0
      src/actions/action_alert.erl
  5. 11 0
      src/actions/action_api.erl
  6. 16 0
      src/actions/action_confirm.erl
  7. 24 0
      src/actions/action_event.erl
  8. 24 0
      src/actions/action_jq.erl
  9. 12 0
      src/actions/action_transfer.erl
  10. 11 0
      src/actions/action_wire.erl
  11. 35 0
      src/elements/element_area.erl
  12. 34 0
      src/elements/element_audio.erl
  13. 12 0
      src/elements/element_blockquote.erl
  14. 21 0
      src/elements/element_button.erl
  15. 28 0
      src/elements/element_canvas.erl
  16. 44 0
      src/elements/element_checkbox.erl
  17. 27 0
      src/elements/element_col.erl
  18. 27 0
      src/elements/element_colgroup.erl
  19. 43 0
      src/elements/element_color.erl
  20. 31 0
      src/elements/element_command.erl
  21. 48 0
      src/elements/element_date.erl
  22. 48 0
      src/elements/element_datetime.erl
  23. 48 0
      src/elements/element_datetime_local.erl
  24. 28 0
      src/elements/element_del.erl
  25. 27 0
      src/elements/element_details.erl
  26. 27 0
      src/elements/element_dropdown.erl
  27. 19 0
      src/elements/element_dtl.erl
  28. 50 0
      src/elements/element_email.erl
  29. 30 0
      src/elements/element_embed.erl
  30. 35 0
      src/elements/element_fieldset.erl
  31. 43 0
      src/elements/element_file.erl
  32. 34 0
      src/elements/element_form.erl
  33. 31 0
      src/elements/element_hidden.erl
  34. 27 0
      src/elements/element_html.erl
  35. 33 0
      src/elements/element_iframe.erl
  36. 18 0
      src/elements/element_image.erl
  37. 48 0
      src/elements/element_input.erl
  38. 40 0
      src/elements/element_input_button.erl
  39. 49 0
      src/elements/element_input_image.erl
  40. 48 0
      src/elements/element_input_time.erl
  41. 28 0
      src/elements/element_ins.erl
  42. 41 0
      src/elements/element_keygen.erl
  43. 13 0
      src/elements/element_label.erl
  44. 11 0
      src/elements/element_legend.erl
  45. 11 0
      src/elements/element_li.erl
  46. 42 0
      src/elements/element_link.erl
  47. 14 0
      src/elements/element_list.erl
  48. 6 0
      src/elements/element_literal.erl
  49. 27 0
      src/elements/element_map.erl
  50. 28 0
      src/elements/element_menu.erl
  51. 31 0
      src/elements/element_meta.erl
  52. 28 0
      src/elements/element_meta_base.erl
  53. 32 0
      src/elements/element_meta_link.erl
  54. 32 0
      src/elements/element_meter.erl
  55. 47 0
      src/elements/element_month.erl
  56. 49 0
      src/elements/element_number.erl
  57. 33 0
      src/elements/element_object.erl
  58. 29 0
      src/elements/element_output.erl
  59. 13 0
      src/elements/element_panel.erl
  60. 28 0
      src/elements/element_param.erl
  61. 48 0
      src/elements/element_password.erl
  62. 28 0
      src/elements/element_progress.erl
  63. 27 0
      src/elements/element_q.erl
  64. 34 0
      src/elements/element_radio.erl
  65. 23 0
      src/elements/element_radiogroup.erl
  66. 46 0
      src/elements/element_range.erl
  67. 41 0
      src/elements/element_reset.erl
  68. 31 0
      src/elements/element_script.erl
  69. 50 0
      src/elements/element_search.erl
  70. 37 0
      src/elements/element_select.erl
  71. 29 0
      src/elements/element_source.erl
  72. 29 0
      src/elements/element_style.erl
  73. 23 0
      src/elements/element_submit.erl
  74. 25 0
      src/elements/element_summary.erl
  75. 33 0
      src/elements/element_table.erl
  76. 13 0
      src/elements/element_td.erl
  77. 49 0
      src/elements/element_tel.erl
  78. 40 0
      src/elements/element_textarea.erl
  79. 20 0
      src/elements/element_textbox.erl
  80. 13 0
      src/elements/element_th.erl
  81. 27 0
      src/elements/element_time.erl
  82. 14 0
      src/elements/element_tr.erl
  83. 31 0
      src/elements/element_track.erl
  84. 49 0
      src/elements/element_url.erl
  85. 36 0
      src/elements/element_video.erl
  86. 48 0
      src/elements/element_week.erl
  87. 99 0
      src/nitro.erl
  88. 186 0
      src/nitro_mochinum.erl
  89. 7 0
      src/nitro_pickle.erl
  90. 18 0
      src/render/wf_event.erl
  91. 11 0
      src/render/wf_render.erl
  92. 13 0
      src/render/wf_render_actions.erl
  93. 47 0
      src/render/wf_render_elements.erl
  94. 28 0
      src/render/wf_tags.erl

+ 18 - 0
LICENSE

@@ -0,0 +1,18 @@
+Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+Software may only be used for the great good and the true happiness of all sentient beings.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 16 - 0
README.md

@@ -0,0 +1,16 @@
+NITRO: Erlang Records DSL for HTML5
+===================================
+
+Features
+--------
+
+* Full HTML5 Support
+* Support for N2O Erlang WebSocket Application Server
+
+Credits
+-------
+
+* Maxim Sokhatsky -- adaptation
+* Rusty Klophaus -- original author
+
+OM A HUM

+ 190 - 0
include/nitro.hrl

@@ -0,0 +1,190 @@
+-ifndef(N2O_HRL).
+-define(N2O_HRL, true).
+
+-record(handler, {name, module, config, state}).
+-record(cx,      {handlers, actions, req, module, lang, path, session, params, form, state=[]}).
+-record(ev,      {module, msg, trigger, name :: api_event | control_event | event | atom() }).
+
+-define(DEFAULT_BASE, {?ELEMENT_BASE(undefined)}).
+-define(DEFAULT_BASE_TAG(Tag), {?ELEMENT_BASE(undefined,Tag,undefined)}).
+-define(ELEMENT_BASE(Module), ?ELEMENT_BASE(Module,undefined,undefined)).
+-define(ELEMENT_BASE(Module,Tag,Delegate),
+        ancestor=element, id, module=Module, delegate=Delegate, validation=[], actions, class=[], style=[], source=[], onmouseover, onkeypress, onchange, onkeyup, onkeydown, onclick,
+        data_fields=[], aria_states=[], body, role, tabindex, show_if=true, html_tag=Tag, title, accesskey, contenteditable, contextmenu, dir, draggable, dropzone, hidden, lang, spellcheck, translate, onafterprint, onbeforeprint, onbeforeunload, onblur, onerror, onfocus, onhashchange, onload, onmessage, onoffline, ononline, onpagehide, onpageshow, onpopstate, onresize, onstorage, onunload).
+-define(ACTION_BASE(Module),
+        ancestor=action, trigger, target, module=Module, actions, source=[]).
+-define(CTRL_BASE(Module), ?ELEMENT_BASE(Module,undefined,Module)).
+
+-record(element, {?ELEMENT_BASE(undefined)}).
+-record(literal, {?ELEMENT_BASE(element_literal)}).
+-record(dtl, {?ELEMENT_BASE(element_dtl), file="index", bindings=[], app=web, folder="priv/templates", ext="html", bind_script=true, js_escape=false }).
+-record(list, {?ELEMENT_BASE(element_list), numbered=false }).
+-record(dropdown, {?ELEMENT_BASE(element_dropdown), options, postback, value, multiple=false, disabled=false, name}).
+-record(radiogroup, {?ELEMENT_BASE(element_radiogroup)}).
+-record(spinner, {?ELEMENT_BASE(element_spinner), image="/nitrogen/spinner.gif"}).
+
+% HTML Document meta
+-record(base,       {?ELEMENT_BASE(element_meta_base), href, target}).
+-record(head,       ?DEFAULT_BASE).
+-record(meta_link,       {?ELEMENT_BASE(element_meta_link), href, hreflang, media, rel, sizes, type}).
+-record(meta,       {?ELEMENT_BASE(element_meta), charset, content, http_equiv, name, type}).
+-record(style,       {?ELEMENT_BASE(element_style), media, scoped, type}).
+-record(title,       ?DEFAULT_BASE).
+
+% HTML Edits
+-record('del',       {?ELEMENT_BASE(element_del), cite, datetime}).
+-record(ins,       {?ELEMENT_BASE(element_ins), cite, datetime}).
+
+% HTML Embedded
+-record(area,       {?ELEMENT_BASE(element_area), alt, coords, href, hreflang, media, target, rel, shape, type}).
+-record(audio,       {?ELEMENT_BASE(element_audio), autoplay, controls, loop, mediagroup, muted, preload, src, width}).
+-record(canvas,       {?ELEMENT_BASE(element_canvas), height, width}).
+-record(embed,       {?ELEMENT_BASE(element_embed), height, src, type, width}).
+-record(iframe,       {?ELEMENT_BASE(element_iframe), height, name, sandbox, seamless, src, srcdoc, width}).
+-record(image,       {?ELEMENT_BASE(element_image), alt, height, ismap, src, usemap, width, image}).
+-record(map,       {?ELEMENT_BASE(element_map), name}).
+-record(object,       {?ELEMENT_BASE(element_object), data, form, height, name, type, usemap, width}).
+-record(param,       {?ELEMENT_BASE(element_param), name, value}).
+-record(source,       {?ELEMENT_BASE(element_source), media, src, type}).
+-record(track,       {?ELEMENT_BASE(element_track), default, kind, label, src, srclang}).
+-record(video,       {?ELEMENT_BASE(element_video), autoplay, controls, height, loop, mediagroup, muted, poster, preload, src, width}).
+
+% HTML Form
+-record(button,       {?ELEMENT_BASE(element_button), autofocus, disabled, form, formaction, formenctype, formmethod, formtarget, formnovalidate, name, type= <<"button">>, value, postback}).
+-record(datalist,       ?DEFAULT_BASE).
+-record(fieldset,       {?ELEMENT_BASE(element_fieldset), disabled, form, name, legend}).
+-record(form,       {?ELEMENT_BASE(element_form), accept_charset, action, autocomplete, enctype, method, name, novalidate, target}).
+-record(keygen,       {?ELEMENT_BASE(element_keygen), autofocus, challenge, disabled, form, keytype, name, postback}).
+-record(legend,       ?DEFAULT_BASE).
+-record(label,       {?ELEMENT_BASE(element_label), for, form, postback}).
+-record(meter,       {?ELEMENT_BASE(element_meter), high, low, max, min, optimum, value, postback}).
+-record(optgroup,       {?ELEMENT_BASE(element_select), disabled, label}).
+-record(option,       {?ELEMENT_BASE(element_select), disabled, label, selected=false, value, postback}).
+-record(output,       {?ELEMENT_BASE(element_output), for, form, name, postback}).
+-record(progress,       {?ELEMENT_BASE(element_progress), max, value, postback}).
+-record(select,       {?ELEMENT_BASE(element_select), autofocus, disabled, form, multiple, name, required, size, postback}).
+-record(textarea,       {?ELEMENT_BASE(element_textarea), autofocus, cols, dirname, disabled, form, maxlength, name, placeholder, readonly, required, rows, wrap, postback, value}).
+
+% HTML Form inputs
+-record(input,       {?ELEMENT_BASE(element_input),  autofocus, disabled, form, name, value, postback, type=[], placeholder, multiple, min, max}).
+-record(input_button,       {?ELEMENT_BASE(element_input_button),  autofocus, disabled, form, name, value, postback}).
+-record(checkbox,           {?ELEMENT_BASE(element_checkbox),  autofocus, checked=false, disabled, form, name, required, value, postback}).
+-record(color,           {?ELEMENT_BASE(element_color),  autocomplete, autofocus, disabled, form, list, name, value, postback}).
+-record(date,           {?ELEMENT_BASE(element_date),  autocomplete, autofocus, disabled, form, list, max, min, name, step, readonly, required, value, postback}).
+-record(datetime,           {?ELEMENT_BASE(element_datetime),  autocomplete, autofocus, disabled, form, list, max, min, name, step, readonly, required, value, postback}).
+-record(datetime_local,           {?ELEMENT_BASE(element_datetime_local),  autocomplete, autofocus, disabled, form, list, max, min, name, step, readonly, required, value, postback}).
+-record(email,           {?ELEMENT_BASE(element_email),  autocomplete, autofocus, disabled, form, list, maxlength, multiple, name, pattern, placeholder, readonly, required, size, value, postback}).
+-record(file,           {?ELEMENT_BASE(element_file),  accept, autofocus, disabled, form, multiple, name, required, postback}).
+-record(hidden,           {?ELEMENT_BASE(element_hidden),  disabled, form, name, value, postback, html_name}).
+-record(input_image,           {?ELEMENT_BASE(element_input_image),  alt, autofocus, disabled, form, formaction, formenctype, formmethod, formnovalue, formtarget, height, name, src, width, postback}).
+-record(month,              {?ELEMENT_BASE(element_month),  alt, autocomplite, autofocus, disabled, form, list, min, max, name, readonly, required, step, value, postback}).
+-record(number,              {?ELEMENT_BASE(element_number),  autocomplete, autofocus, disabled, form, list, max, min, name, placeholder, readonly, required, step, value, postback}).
+-record(password,              {?ELEMENT_BASE(element_password),  autocomplete, autofocus, disabled, form, maxlength, name, pattern, placeholder, readonly, required, size, value, postback}).
+-record(radio,              {?ELEMENT_BASE(element_radio),  autofocus, checked, disabled, form, name, required, value, postback, html_name}).
+-record(range,              {?ELEMENT_BASE(element_range),  autocomplete, autofocus, disabled, form, list, max=100, min=0, name, step=1, value, postback}).
+-record(reset,              {?ELEMENT_BASE(element_reset),  autofocus, disabled, form, name, value, postback}).
+-record(search,              {?ELEMENT_BASE(element_search),  autocomplete, autofocus, dirname, disabled, form, list, maxlength, name, pattern, placeholder, readonly, required, size, value, postback}).
+-record(submit,              {?ELEMENT_BASE(element_submit),  autofocus, disabled, form, formaction, formenctype, formmethod, formnovalidate, formtarget, name, value, postback, click}).
+-record(tel,              {?ELEMENT_BASE(element_tel),  autocomplete, autofocus, disabled, form, list, maxlength, name, pattern, placeholder, readonly, required, size, value, postback}).
+-record(textbox,              {?ELEMENT_BASE(element_textbox),  autocomplete, autofocus, dirname, disabled, form, list, maxlength, name, pattern, placeholder, readony, required, size, value, postback}).
+-record(input_time,              {?ELEMENT_BASE(element_input_time),  autocomplete, autofocus, disabled, form, list, max, min, name, step, readonly, required, value, postback}).
+-record(url,              {?ELEMENT_BASE(element_url),  autocomplete, autofocus, disabled, form, list, maxlength, name, pattern, placeholder, readonly, required, size, value, postback}).
+-record(week,              {?ELEMENT_BASE(element_week),  autocomplete, autofocus, disabled, form, list, max, min, name, readonly, required, step, value, postback}).
+
+% HTML Interactive
+-record(command,       {?ELEMENT_BASE(element_command),  checked, disabled, icon, label, radiogroup, type= <<"command">>}).
+-record(details,       {?ELEMENT_BASE(element_details),  open}).
+-record(menu,       {?ELEMENT_BASE(element_menu),  label, type}).
+-record(summary,       ?DEFAULT_BASE).
+
+% HTML Grouping content
+-record(blockquote,		{?ELEMENT_BASE(element_blockquote),  cite}).
+-record(br,       		?DEFAULT_BASE).
+-record(dd,       		?DEFAULT_BASE).
+-record('div',      	?DEFAULT_BASE_TAG(<<"div">>)).
+-record(dl,       		?DEFAULT_BASE).
+-record(dt,       		?DEFAULT_BASE).
+-record(figcaption,		?DEFAULT_BASE).
+-record(figure,       	?DEFAULT_BASE).
+-record(hr,       		?DEFAULT_BASE).
+-record(li,             {?ELEMENT_BASE(element_li),  value}).
+-record(ol,             ?DEFAULT_BASE).
+-record(p,       		?DEFAULT_BASE).
+-record(panel,          ?DEFAULT_BASE_TAG(<<"div">>)).
+-record(pre,       		?DEFAULT_BASE).
+-record(ul,       		?DEFAULT_BASE).
+
+% HTML Root
+-record(html,			{?ELEMENT_BASE(element_html), manifest}).
+
+% HTML Scripting
+-record(script,			{?ELEMENT_BASE(element_script),  async, charset, defer, src, type}).
+-record(noscript,      	?DEFAULT_BASE).
+
+% HTML Sections
+-record(body,       	?DEFAULT_BASE).
+-record(section,    	?DEFAULT_BASE).
+-record(nav,        	?DEFAULT_BASE).
+-record(article,    	?DEFAULT_BASE).
+-record(aside,      	?DEFAULT_BASE).
+-record(h1,         	?DEFAULT_BASE).
+-record(h2,         	?DEFAULT_BASE).
+-record(h3,         	?DEFAULT_BASE).
+-record(h4,         	?DEFAULT_BASE).
+-record(h5,         	?DEFAULT_BASE).
+-record(h6,         	?DEFAULT_BASE).
+-record(header,     	?DEFAULT_BASE).
+-record(hgroup,     	?DEFAULT_BASE).
+-record(footer,     	?DEFAULT_BASE).
+-record(address,    	?DEFAULT_BASE).
+-record(main,       	?DEFAULT_BASE).
+
+% HTML Table
+-record(caption,       	?DEFAULT_BASE).
+-record(col,            {?ELEMENT_BASE(element_col),  span}).
+-record(colgroup,       {?ELEMENT_BASE(element_colgroup), col, span}).
+-record(table,          {?ELEMENT_BASE(element_table),  caption, colgroup, border, footer, header}).
+-record(tbody,          ?DEFAULT_BASE).
+-record(td, 			{?ELEMENT_BASE(element_td), colspan=1, headers, rowspan=1, scope}).
+-record(tfoot,       	?DEFAULT_BASE).
+-record(th, 			{?ELEMENT_BASE(element_th), colspan=1, headers, rowspan=1, scope}).
+-record(thead,       	?DEFAULT_BASE).
+-record(tr, 			{?ELEMENT_BASE(element_tr), cells, postback}).
+
+% HTML Text-level semantics
+-record(link,           {?ELEMENT_BASE(element_link),  href, hreflang, media, rel, target, type, url="javascript:void(0);", download, name, postback}).
+-record(abbr,       	?DEFAULT_BASE).
+-record(b,       		?DEFAULT_BASE).
+-record(bdi,       		?DEFAULT_BASE).
+-record(bdo,       		?DEFAULT_BASE).
+-record(cite,       	?DEFAULT_BASE).
+-record(code,       	?DEFAULT_BASE).
+-record(dfn,       		?DEFAULT_BASE).
+-record(em,       		?DEFAULT_BASE).
+-record(i,       		?DEFAULT_BASE).
+-record(kbd,       		?DEFAULT_BASE).
+-record(mark,       	?DEFAULT_BASE).
+-record(q,              {?ELEMENT_BASE(element_q),  cite}).
+-record(rt,       		?DEFAULT_BASE).
+-record(rp,       		?DEFAULT_BASE).
+-record(ruby,       	?DEFAULT_BASE).
+-record(s,       		?DEFAULT_BASE).
+-record(samp,       	?DEFAULT_BASE).
+-record(small,       	?DEFAULT_BASE).
+-record(span,       	?DEFAULT_BASE).
+-record(strong,       	?DEFAULT_BASE).
+-record(sub,       		?DEFAULT_BASE).
+-record(sup,       		?DEFAULT_BASE).
+-record(time,           {?ELEMENT_BASE(element_time),  datetime}).
+-record(u,       		?DEFAULT_BASE).
+-record(var,       		?DEFAULT_BASE).
+
+% Actions
+-record(action,  {?ACTION_BASE(undefined)}).
+-record(wire,    {?ACTION_BASE(action_wire)}).
+-record(api,     {?ACTION_BASE(action_api), name, tag, delegate }).
+-record(event,   {?ACTION_BASE(action_event), type=default, postback, delegate}).
+-record(alert,   {?ACTION_BASE(action_alert), text}).
+-record(confirm, {?ACTION_BASE(action_confirm), text, postback, delegate}).
+-record(jq,      {?ACTION_BASE(action_jq), property, method, args=[], right, format="~s"}).
+-record(transfer,{?ACTION_BASE(action_transfer), state, events=[] }).

+ 6 - 0
src/actions/action_alert.erl

@@ -0,0 +1,6 @@
+-module(action_alert).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Record) -> nitro:f("alert(\"~s\");", [nitro:js_escape(Record#alert.text)]).

+ 11 - 0
src/actions/action_api.erl

@@ -0,0 +1,11 @@
+-module(action_api).
+-author('Maxim Sokhatsky').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Record) ->
+    Name = Record#api.name,
+    Data = "utf8_toByteArray(JSON.stringify(data))",
+    PostbackScript = wf_event:new(Name, "document", Record#api.delegate, api_event, Data, []),
+    nitro:f("~s = function(data) {",  [Name]) ++ PostbackScript ++ "};".
+

+ 16 - 0
src/actions/action_confirm.erl

@@ -0,0 +1,16 @@
+-module(action_confirm).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Record) -> 
+    Control = Record#confirm.target,
+    Delegate = Record#confirm.delegate,
+    Postback = Record#confirm.postback,
+    PostbackScript = wf_event:new(Postback, Control, Delegate, event, "[]", []),
+    [
+        nitro:f("if (confirm(\"~s\")) {", [nitro:js_escape(Record#confirm.text)]),
+        PostbackScript,
+        "}"
+    ].
+

+ 24 - 0
src/actions/action_event.erl

@@ -0,0 +1,24 @@
+-module(action_event).
+-author('Maxim Sokhatsky').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(#event{source=undefined}) -> [];
+
+render_action(#event{postback={bin,Value},target=Control,type=Type}) ->
+    PostbackBin = wf_event:new(bin,Value),
+    [list_to_binary([<<"qi('">>,nitro:to_binary(Control),<<"').addEventListener('">>,
+        nitro:to_binary(Type),<<"',function (event){">>,PostbackBin,<<"});">>])];
+
+render_action(#event{postback=Postback,actions=_Actions,source=Source,target=Control,type=Type,delegate=Delegate}) ->
+    Element = nitro:to_list(Control),
+    Data=list_to_binary([<<"[tuple(tuple(utf8_toByteArray('">>,Element,<<"'),bin('detail')),event.detail)">>,
+         [ begin {SrcType,Src2}=case is_atom(Src) of
+                 true -> { <<"atom">>,atom_to_list(Src) };
+                 false -> { <<"utf8_toByteArray">>,Src } end,
+             [ <<",tuple(">>,SrcType,<<"('">>,Src2,<<"'),querySource('">>,Src2,<<"'))">> ]
+             end || Src <- Source ],<<"]">>]),
+    PostbackBin = wf_event:new(Postback, Element, Delegate, event, Data, Source),
+    [list_to_binary([<<"{var x=qi('">>,Element,<<"'); x && x.addEventListener('">>,
+        nitro:to_binary(Type),<<"',function (event){">>,
+        PostbackBin,<<"});};">>])].

+ 24 - 0
src/actions/action_jq.erl

@@ -0,0 +1,24 @@
+-module(action_jq).
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Record=#jq{property=undefined,target=Target,method=Methods,args=Args0,format=_F}) ->
+    Args = case Record#jq.format of "'~s'" -> [nitro:render(Args0)]; _ -> Args0 end,
+    RenderedArgs = string:join([ case A of 
+        A when is_tuple(A) -> nitro:render(A);
+        A when is_list(A) -> A;
+        A when is_integer(A) -> nitro:to_list(A);
+        A -> A end || A <- Args],","),
+    string:join([ nitro:f("qi('~s').~s("++Record#jq.format++");",
+        [nitro:to_list(Target),nitro:to_list(Method),RenderedArgs]) || Method <- Methods],[]);
+
+render_action(#jq{target=T,method=undefined,property=P,args=simple,right=R,format=_F}) ->
+    nitro:f("~s.~s = '~s';",
+        [nitro:to_list(T),nitro:to_list(P),binary_to_list(iolist_to_binary(nitro:render(R)))]);
+
+render_action(#jq{target=T,method=undefined,property=P,right=undefined}) ->
+    nitro:f("qi('~s').~s;", [nitro:to_list(T),nitro:to_list(P)]);
+
+render_action(#jq{target=T,method=undefined,property=P,right=R,format=_F}) ->
+    nitro:f("qi('~s').~s = '~s';",
+        [nitro:to_list(T),nitro:to_list(P),binary_to_list(iolist_to_binary(nitro:render(R)))]).

+ 12 - 0
src/actions/action_transfer.erl

@@ -0,0 +1,12 @@
+-module(action_transfer).
+-author('Andrey Martemyanov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Record) ->
+    case Record#transfer.state of
+        undefined -> ok;
+        List when is_list(List) -> [ erlang:put(K,V) || {K,V} <- List ];
+        Single -> erlang:put(state,Single) end,
+    Events = case Record#transfer.events of E when is_list(E) -> E; E -> [E] end,
+    [ self() ! M || M <- Events ], ok.

+ 11 - 0
src/actions/action_wire.erl

@@ -0,0 +1,11 @@
+-module(action_wire).
+-author('Maxim Sokhatsky').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(#wire{actions=Actions}) -> nitro:render(Actions);
+render_action(S) when is_list(S) -> S;
+render_action(_) -> [].
+
+wire(Actions) -> Actions = case get(actions) of undefined -> []; E -> E end,
+                 put(actions,Actions++[#wire{actions=Actions}]).

+ 35 - 0
src/elements/element_area.erl

@@ -0,0 +1,35 @@
+-module(element_area).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#area.accesskey},
+      {<<"class">>, Record#area.class},
+      {<<"contenteditable">>, case Record#area.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#area.contextmenu},
+      {<<"dir">>, case Record#area.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#area.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#area.dropzone},
+      {<<"hidden">>, case Record#area.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#area.id},
+      {<<"lang">>, Record#area.lang},
+      {<<"spellcheck">>, case Record#area.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#area.style},
+      {<<"tabindex">>, Record#area.tabindex},
+      {<<"title">>, Record#area.title},
+      {<<"translate">>, case Record#area.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"alt">>,Record#area.alt},
+      {<<"coords">>,Record#area.coords},
+      {<<"href">>,Record#area.href},
+      {<<"hreflang">>,Record#area.hreflang},
+      {<<"media">>,Record#area.media},
+      {<<"rel">>,Record#area.rel},
+      {<<"shape">>, case Record#area.shape of "rect" -> "rect"; "circle" -> "circle"; "poly" -> "poly"; "default" -> "default"; _ -> undefined end},
+      {<<"target">>,Record#area.target},
+      {<<"type">>,Record#area.type} | Record#area.data_fields
+    ],
+    wf_tags:emit_tag(<<"area">>, List).

+ 34 - 0
src/elements/element_audio.erl

@@ -0,0 +1,34 @@
+-module(element_audio).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#audio.accesskey},
+      {<<"class">>, Record#audio.class},
+      {<<"contenteditable">>, case Record#audio.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#audio.contextmenu},
+      {<<"dir">>, case Record#audio.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#audio.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#audio.dropzone},
+      {<<"hidden">>, case Record#audio.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#audio.id},
+      {<<"lang">>, Record#audio.lang},
+      {<<"spellcheck">>, case Record#audio.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#audio.style},
+      {<<"tabindex">>, Record#audio.tabindex},
+      {<<"title">>, Record#audio.title},
+      {<<"translate">>, case Record#audio.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autoplay">>, case Record#audio.autoplay of true -> "autoplay"; _ -> undefined end},      
+      {<<"controls">>, case Record#audio.controls of true -> "controls"; _ -> undefined end},      
+      {<<"loop">>, case Record#audio.loop of true -> "loop"; _ -> undefined end},            
+      {<<"mediagroup">>, Record#audio.mediagroup},      
+      {<<"muted">>, case Record#audio.muted of true -> "muted"; _ -> undefined end},
+      {<<"preload">>, case Record#audio.preload of "auto" -> "auto"; "none" -> "none"; "metadata" -> "metadata"; _ -> undefined end},
+      {<<"src">>, Record#audio.src},
+      {<<"width">>, Record#audio.width} | Record#audio.data_fields
+    ],
+    wf_tags:emit_tag(<<"audio">>, nitro:render(case Record#audio.body of undefined -> []; B -> B end), List).

+ 12 - 0
src/elements/element_blockquote.erl

@@ -0,0 +1,12 @@
+-module (element_blockquote).
+-author('Andrew Zadorozhny').
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+  wf_tags:emit_tag(<<"blockquote">>, nitro:render(Record#blockquote.body), [
+      {<<"id">>, Record#blockquote.id},
+      {<<"class">>, Record#blockquote.class},
+      {<<"style">>, Record#blockquote.style},
+      {<<"cite">>, Record#blockquote.cite}  | Record#blockquote.data_fields
+  ]).

+ 21 - 0
src/elements/element_button.erl

@@ -0,0 +1,21 @@
+-module(element_button).
+-author('Andrew Zadorozhny').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#button.postback of
+        undefined -> Record#button.id;
+        Postback ->
+          ID = case Record#button.id of undefined -> wf:temp_id(); I -> I end,
+          wf:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#button.source, delegate=Record#button.delegate }),
+          ID end,
+    wf_tags:emit_tag(<<"button">>, wf:render(Record#button.body), [
+        {<<"id">>, Id},
+        {<<"type">>, Record#button.type},
+        {<<"name">>, Record#button.name},
+        {<<"class">>, Record#button.class},
+        {<<"style">>, Record#button.style},
+        {<<"disabled">>, if Record#button.disabled == true -> "disabled"; true -> undefined end},
+        {<<"value">>, Record#button.value}  | Record#button.data_fields ]).

+ 28 - 0
src/elements/element_canvas.erl

@@ -0,0 +1,28 @@
+-module(element_canvas).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#canvas.accesskey},
+      {<<"class">>, Record#canvas.class},
+      {<<"contenteditable">>, case Record#canvas.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#canvas.contextmenu},
+      {<<"dir">>, case Record#canvas.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#canvas.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#canvas.dropzone},
+      {<<"hidden">>, case Record#canvas.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#canvas.id},
+      {<<"lang">>, Record#canvas.lang},
+      {<<"spellcheck">>, case Record#canvas.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#canvas.style},
+      {<<"tabindex">>, Record#canvas.tabindex},
+      {<<"title">>, Record#canvas.title},
+      {<<"translate">>, case Record#canvas.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"height">>,Record#canvas.height},
+      {<<"width">>,Record#canvas.width} | Record#canvas.data_fields
+    ],
+    wf_tags:emit_tag(<<"canvas">>, nitro:render(case Record#canvas.body of undefined -> []; B -> B end), List).

+ 44 - 0
src/elements/element_checkbox.erl

@@ -0,0 +1,44 @@
+-module(element_checkbox).
+-author('Rusty Klophaus, Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+    Id = case Record#checkbox.id of undefined -> nitro:temp_id(); I->I end,
+    case Record#checkbox.postback of
+        undefined -> ignore;
+        Postback -> nitro:wire(#event { type=change, postback=Postback, target=Id, source=Record#checkbox.source, delegate=Record#checkbox.delegate })
+    end,
+   Label = [ wf_tags:emit_tag(<<"input">>, [], [
+      % global
+      {<<"accesskey">>, Record#checkbox.accesskey},
+      {<<"class">>, Record#checkbox.class},
+      {<<"contenteditable">>, case Record#checkbox.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#checkbox.contextmenu},
+      {<<"dir">>, case Record#checkbox.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#checkbox.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#checkbox.dropzone},
+      {<<"hidden">>, case Record#checkbox.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#checkbox.lang},
+      {<<"spellcheck">>, case Record#checkbox.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#checkbox.style},
+      {<<"tabindex">>, Record#checkbox.tabindex},
+      {<<"title">>, Record#checkbox.title},
+      {<<"translate">>, case Record#checkbox.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,Record#checkbox.autofocus},
+      {<<"checked">>, if Record#checkbox.checked==true -> <<"checked">>; true -> undefined end},
+      {<<"data-toggle">>, <<"checkbox">>},
+      {<<"disabled">>, if Record#checkbox.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>, Record#checkbox.form},
+      {<<"name">>, Record#checkbox.name},            
+      {<<"required">>, if Record#checkbox.required == true -> "required"; true -> undefined end},
+      {<<"type">>, <<"checkbox">>},
+      {<<"value">>, Record#checkbox.value} | Record#checkbox.data_fields
+      ]),
+      case Record#checkbox.body of undefined -> []; B -> B end ],
+    wf_tags:emit_tag(<<"label">>, nitro:render(Label), [
+        {<<"class">>, Record#checkbox.class},
+        {<<"style">>, Record#checkbox.style},
+        {<<"for">>, Id} ]).

+ 27 - 0
src/elements/element_col.erl

@@ -0,0 +1,27 @@
+-module(element_col).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#col.accesskey},
+      {<<"class">>, Record#col.class},
+      {<<"contenteditable">>, case Record#col.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#col.contextmenu},
+      {<<"dir">>, case Record#col.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#col.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#col.dropzone},
+      {<<"hidden">>, case Record#col.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#col.id},
+      {<<"lang">>, Record#col.lang},
+      {<<"spellcheck">>, case Record#col.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#col.style},
+      {<<"tabindex">>, Record#col.tabindex},
+      {<<"title">>, Record#col.title},
+      {<<"translate">>, case Record#col.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"span">>,Record#col.span} | Record#col.data_fields
+    ],
+    wf_tags:emit_tag(<<"col">>, nitro:render(case Record#col.body of undefined -> []; B -> B end), List).

+ 27 - 0
src/elements/element_colgroup.erl

@@ -0,0 +1,27 @@
+-module(element_colgroup).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#colgroup.accesskey},
+      {<<"class">>, Record#colgroup.class},
+      {<<"contenteditable">>, case Record#colgroup.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#colgroup.contextmenu},
+      {<<"dir">>, case Record#colgroup.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#colgroup.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#colgroup.dropzone},
+      {<<"hidden">>, case Record#colgroup.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#colgroup.id},
+      {<<"lang">>, Record#colgroup.lang},
+      {<<"spellcheck">>, case Record#colgroup.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#colgroup.style},
+      {<<"tabindex">>, Record#colgroup.tabindex},
+      {<<"title">>, Record#colgroup.title},
+      {<<"translate">>, case Record#colgroup.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"span">>,Record#colgroup.span} | Record#colgroup.data_fields
+    ],
+    wf_tags:emit_tag(<<"colgroup">>, nitro:render(case Record#colgroup.body of undefined -> []; B -> B end), List).

+ 43 - 0
src/elements/element_color.erl

@@ -0,0 +1,43 @@
+-module(element_color).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#color.postback of
+        undefined -> Record#color.id;
+        Postback ->
+          ID = case Record#color.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#color.source, delegate=Record#color.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#color.accesskey},
+      {<<"class">>, Record#color.class},
+      {<<"contenteditable">>, case Record#color.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#color.contextmenu},
+      {<<"dir">>, case Record#color.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#color.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#color.dropzone},
+      {<<"hidden">>, case Record#color.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#color.lang},
+      {<<"spellcheck">>, case Record#color.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#color.style},
+      {<<"tabindex">>, Record#color.tabindex},
+      {<<"title">>, Record#color.title},
+      {<<"translate">>, case Record#color.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>,case Record#color.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#color.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#color.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#color.form},
+      {<<"list">>,Record#color.list},      
+      {<<"name">>,Record#color.name},
+      {<<"type">>, <<"color">>},
+      {<<"value">>,nitro:js_escape(Record#color.value)} | Record#color.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#color.body), List).

+ 31 - 0
src/elements/element_command.erl

@@ -0,0 +1,31 @@
+-module(element_command).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#command.accesskey},
+      {<<"class">>, Record#command.class},
+      {<<"contenteditable">>, case Record#command.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#command.contextmenu},
+      {<<"dir">>, case Record#command.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#command.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#command.dropzone},
+      {<<"hidden">>, case Record#command.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#command.id},
+      {<<"lang">>, Record#command.lang},
+      {<<"spellcheck">>, case Record#command.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#command.style},
+      {<<"tabindex">>, Record#command.tabindex},
+      {<<"title">>, Record#command.title},
+      {<<"translate">>, case Record#command.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},
+      % spec
+      {<<"disabled">>, if Record#command.disabled == true -> "disabled"; true -> undefined end},
+      {<<"icon">>, Record#command.icon},
+      {<<"label">>, Record#command.label},
+      {<<"radiogroup">>, Record#command.radiogroup},
+      {<<"type">>, case Record#command.type of "command" -> "command"; "radio" -> "radio"; "checkbox" -> "checkbox"; _ -> undefined end} | Record#command.data_fields
+    ],
+    wf_tags:emit_tag(<<"command">>, List).

+ 48 - 0
src/elements/element_date.erl

@@ -0,0 +1,48 @@
+-module(element_date).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#date.postback of
+        undefined -> Record#date.id;
+        Postback ->
+          ID = case Record#date.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#date.source, delegate=Record#date.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#date.accesskey},
+      {<<"class">>, Record#date.class},
+      {<<"contenteditable">>, case Record#date.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#date.contextmenu},
+      {<<"dir">>, case Record#date.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#date.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#date.dropzone},
+      {<<"hidden">>, case Record#date.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#date.lang},
+      {<<"spellcheck">>, case Record#date.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#date.style},
+      {<<"tabindex">>, Record#date.tabindex},
+      {<<"title">>, Record#date.title},
+      {<<"translate">>, case Record#date.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#date.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#date.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#date.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#date.form},
+      {<<"list">>,Record#date.list},
+      {<<"max">>,Record#date.max},
+      {<<"min">>,Record#date.min},
+      {<<"name">>,Record#date.name},
+      {<<"readonly">>,if Record#date.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#date.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#date.step},
+      {<<"type">>, <<"date">>},
+      {<<"value">>,nitro:js_escape(Record#date.value)} | Record#date.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#date.body), List).

+ 48 - 0
src/elements/element_datetime.erl

@@ -0,0 +1,48 @@
+-module(element_datetime).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#datetime.postback of
+        undefined -> Record#datetime.id;
+        Postback ->
+          ID = case Record#datetime.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#datetime.source, delegate=Record#datetime.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#datetime.accesskey},
+      {<<"class">>, Record#datetime.class},
+      {<<"contenteditable">>, case Record#datetime.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#datetime.contextmenu},
+      {<<"dir">>, case Record#datetime.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#datetime.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#datetime.dropzone},
+      {<<"hidden">>, case Record#datetime.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#datetime.lang},
+      {<<"spellcheck">>, case Record#datetime.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#datetime.style},
+      {<<"tabindex">>, Record#datetime.tabindex},
+      {<<"title">>, Record#datetime.title},
+      {<<"translate">>, case Record#datetime.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#datetime.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#datetime.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#datetime.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#datetime.form},
+      {<<"list">>,Record#datetime.list},
+      {<<"max">>,Record#datetime.max},
+      {<<"min">>,Record#datetime.min},
+      {<<"name">>,Record#datetime.name},
+      {<<"readonly">>,if Record#datetime.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#datetime.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#datetime.step},
+      {<<"type">>, <<"datetime">>},
+      {<<"value">>,nitro:js_escape(Record#datetime.value)} | Record#datetime.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#datetime.body), List).

+ 48 - 0
src/elements/element_datetime_local.erl

@@ -0,0 +1,48 @@
+-module(element_datetime_local).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#datetime_local.postback of
+        undefined -> Record#datetime_local.id;
+        Postback ->
+          ID = case Record#datetime_local.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#datetime_local.source, delegate=Record#datetime_local.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#datetime_local.accesskey},
+      {<<"class">>, Record#datetime_local.class},
+      {<<"contenteditable">>, case Record#datetime_local.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#datetime_local.contextmenu},
+      {<<"dir">>, case Record#datetime_local.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#datetime_local.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#datetime_local.dropzone},
+      {<<"hidden">>, case Record#datetime_local.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#datetime_local.lang},
+      {<<"spellcheck">>, case Record#datetime_local.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#datetime_local.style},
+      {<<"tabindex">>, Record#datetime_local.tabindex},
+      {<<"title">>, Record#datetime_local.title},
+      {<<"translate">>, case Record#datetime_local.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#datetime_local.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#datetime_local.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#datetime_local.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#datetime_local.form},
+      {<<"list">>,Record#datetime_local.list},
+      {<<"max">>,Record#datetime_local.max},
+      {<<"min">>,Record#datetime_local.min},
+      {<<"name">>,Record#datetime_local.name},
+      {<<"readonly">>,if Record#datetime_local.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#datetime_local.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#datetime_local.step},
+      {<<"type">>, <<"datetime_local">>},
+      {<<"value">>,nitro:js_escape(Record#datetime_local.value)} | Record#datetime_local.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#datetime_local.body), List).

+ 28 - 0
src/elements/element_del.erl

@@ -0,0 +1,28 @@
+-module(element_del).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#del.accesskey},
+      {<<"class">>, Record#del.class},
+      {<<"contenteditable">>, case Record#del.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#del.contextmenu},
+      {<<"dir">>, case Record#del.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#del.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#del.dropzone},
+      {<<"hidden">>, case Record#del.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#del.id},
+      {<<"lang">>, Record#del.lang},
+      {<<"spellcheck">>, case Record#del.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#del.style},
+      {<<"tabindex">>, Record#del.tabindex},
+      {<<"title">>, Record#del.title},
+      {<<"translate">>, case Record#del.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"cite">>, Record#del.cite},
+      {<<"datetime">>, Record#del.datetime} | Record#del.data_fields
+    ],
+    wf_tags:emit_tag(<<"del">>, nitro:render(case Record#del.body of undefined -> []; B -> B end), List).

+ 27 - 0
src/elements/element_details.erl

@@ -0,0 +1,27 @@
+-module(element_details).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#details.accesskey},
+      {<<"class">>, Record#details.class},
+      {<<"contenteditable">>, case Record#details.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#details.contextmenu},
+      {<<"dir">>, case Record#details.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#details.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#details.dropzone},
+      {<<"hidden">>, case Record#details.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#details.id},
+      {<<"lang">>, Record#details.lang},
+      {<<"spellcheck">>, case Record#details.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#details.style},
+      {<<"tabindex">>, Record#details.tabindex},
+      {<<"title">>, Record#details.title},
+      {<<"translate">>, case Record#details.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"open">>, case Record#details.open of true -> "open"; _ -> undefined end} | Record#details.data_fields
+    ],
+    wf_tags:emit_tag(<<"details">>, nitro:render(case Record#details.body of undefined -> []; B -> B end), List).

+ 27 - 0
src/elements/element_dropdown.erl

@@ -0,0 +1,27 @@
+-module(element_dropdown).
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record = #dropdown{}) -> 
+    ID = case Record#dropdown.id of undefined -> nitro:temp_id(); I->I end,
+    case Record#dropdown.postback of
+         undefined -> skip;
+         Postback -> nitro:wire(#event { type=click, postback=Postback, target=ID,
+                        source=Record#dropdown.source, delegate=Record#dropdown.delegate } ) end,
+
+    Opts = [wf_tags:emit_tag(<<"option">>, [O#option.label], [
+      {<<"disabled">>, O#option.disabled},
+      {<<"label">>, O#option.label},
+      {<<"selected">>, case O#option.selected of true -> <<"selected">>; _-> undefined end},
+      {<<"value">>, O#option.value}
+    ])|| O = #option{show_if=Visible} <- Record#dropdown.options, Visible == true],
+
+    wf_tags:emit_tag(<<"select">>, Opts, [
+        {<<"id">>, Record#dropdown.id},
+        {<<"class">>, Record#dropdown.class},
+        {<<"style">>, Record#dropdown.style},
+        {<<"name">>, Record#dropdown.name},
+        {<<"disabled">>, case Record#dropdown.disabled of true -> <<"disabled">>; _-> undefined end},
+        {<<"multiple">>, case Record#dropdown.multiple of true -> <<"multiple">>; _-> undefined end}|
+        Record#dropdown.data_fields
+    ]).

+ 19 - 0
src/elements/element_dtl.erl

@@ -0,0 +1,19 @@
+-module(element_dtl).
+-author('Maxim Sokhatsky').
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record=#dtl{}) ->
+    M = list_to_atom(nitro:to_list(Record#dtl.file) ++ "_view"),
+    %File = case code:lib_dir(nitro:to_atom(Record#dtl.app)) of
+                %{error,bad_name} -> nitro:to_list(Record#dtl.app);
+                %A -> A end ++ "/" ++ nitro:to_list(Record#dtl.folder)
+         %++ "/" ++ nitro:to_list(Record#dtl.file) ++ "." ++ nitro:to_list(Record#dtl.ext),
+    {ok,R} = render(M, Record#dtl.js_escape, [{K,nitro:render(V)} || {K,V} <- Record#dtl.bindings] ++
+        if Record#dtl.bind_script==true -> [{script,nitro:script()}]; true-> [] end),
+    R.
+
+render(M, true, Args) ->
+    {ok, R} = M:render(Args),
+    {ok, nitro:js_escape(R)};
+render(M, _, Args) -> M:render(Args).

+ 50 - 0
src/elements/element_email.erl

@@ -0,0 +1,50 @@
+-module(element_email).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#email.postback of
+        undefined -> Record#email.id;
+        Postback ->
+          ID = case Record#email.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#email.source, delegate=Record#email.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#email.accesskey},
+      {<<"class">>, Record#email.class},
+      {<<"contenteditable">>, case Record#email.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#email.contextmenu},
+      {<<"dir">>, case Record#email.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#email.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#email.dropzone},
+      {<<"hidden">>, case Record#email.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#email.lang},
+      {<<"spellcheck">>, case Record#email.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#email.style},
+      {<<"tabindex">>, Record#email.tabindex},
+      {<<"title">>, Record#email.title},
+      {<<"translate">>, case Record#email.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#email.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#email.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#email.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#email.form},
+      {<<"list">>,Record#email.list},
+      {<<"maxlength">>,Record#email.maxlength},
+      {<<"multiple">>,if Record#email.multiple == true -> "multiple"; true -> undefined end},
+      {<<"name">>,Record#email.name},
+      {<<"pattern">>,Record#email.pattern},
+      {<<"placeholder">>,Record#email.placeholder},
+      {<<"readonly">>,if Record#email.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#email.required == true -> "required"; true -> undefined end}, 
+      {<<"size">>,Record#email.size},
+      {<<"type">>, <<"email">>},
+      {<<"value">>,nitro:js_escape(Record#email.value)} | Record#email.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#email.body), List).

+ 30 - 0
src/elements/element_embed.erl

@@ -0,0 +1,30 @@
+-module(element_embed).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#embed.accesskey},
+      {<<"class">>, Record#embed.class},
+      {<<"contenteditable">>, case Record#embed.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#embed.contextmenu},
+      {<<"dir">>, case Record#embed.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#embed.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#embed.dropzone},
+      {<<"hidden">>, case Record#embed.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#embed.id},
+      {<<"lang">>, Record#embed.lang},
+      {<<"spellcheck">>, case Record#embed.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#embed.style},
+      {<<"tabindex">>, Record#embed.tabindex},
+      {<<"title">>, Record#embed.title},
+      {<<"translate">>, case Record#embed.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"height">>,Record#embed.height},      
+      {<<"src">>,Record#embed.src},
+      {<<"type">>,Record#embed.type},
+      {<<"width">>,Record#embed.width} | Record#embed.data_fields
+    ],
+    wf_tags:emit_tag(<<"embed">>, List).

+ 35 - 0
src/elements/element_fieldset.erl

@@ -0,0 +1,35 @@
+-module(element_fieldset).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#fieldset.accesskey},
+      {<<"class">>, Record#fieldset.class},
+      {<<"contenteditable">>, case Record#fieldset.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#fieldset.contextmenu},
+      {<<"dir">>, case Record#fieldset.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#fieldset.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#fieldset.dropzone},
+      {<<"hidden">>, case Record#fieldset.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#fieldset.id},
+      {<<"lang">>, Record#fieldset.lang},
+      {<<"spellcheck">>, case Record#fieldset.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#fieldset.style},
+      {<<"tabindex">>, Record#fieldset.tabindex},
+      {<<"title">>, Record#fieldset.title},
+      {<<"translate">>, case Record#fieldset.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"disabled">>, if Record#fieldset.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#fieldset.form},
+      {<<"name">>,Record#fieldset.name} | Record#fieldset.data_fields
+    ],
+    wf_tags:emit_tag(
+      <<"fieldset">>,
+      [
+        wf_tags:emit_tag(<<"legend">>, nitro:render(case Record#fieldset.legend of undefined -> []; B -> B end), []), 
+        nitro:render(case Record#fieldset.body of undefined -> []; B -> B end)
+      ], 
+      List).

+ 43 - 0
src/elements/element_file.erl

@@ -0,0 +1,43 @@
+-module(element_file).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#file.postback of
+        undefined -> Record#file.id;
+        Postback ->
+          ID = case Record#file.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#file.source, delegate=Record#file.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#file.accesskey},
+      {<<"class">>, Record#file.class},
+      {<<"contenteditable">>, case Record#file.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#file.contextmenu},
+      {<<"dir">>, case Record#file.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#file.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#file.dropzone},
+      {<<"hidden">>, case Record#file.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#file.lang},
+      {<<"spellcheck">>, case Record#file.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#file.style},
+      {<<"tabindex">>, Record#file.tabindex},
+      {<<"title">>, Record#file.title},
+      {<<"translate">>, case Record#file.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"accept">>,Record#file.accept},
+      {<<"autofocus">>,if Record#file.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#file.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#file.form},
+      {<<"multiple">>,if Record#file.multiple == true -> "multiple"; true -> undefined end},
+      {<<"name">>,Record#file.name},
+      {<<"required">>,if Record#file.required == true -> "required"; true -> undefined end}, 
+      {<<"type">>, <<"file">>} | Record#file.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#file.body), List).

+ 34 - 0
src/elements/element_form.erl

@@ -0,0 +1,34 @@
+-module(element_form).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#form.accesskey},
+      {<<"class">>, Record#form.class},
+      {<<"contenteditable">>, case Record#form.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#form.contextmenu},
+      {<<"dir">>, case Record#form.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#form.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#form.dropzone},
+      {<<"hidden">>, case Record#form.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#form.id},
+      {<<"lang">>, Record#form.lang},
+      {<<"spellcheck">>, case Record#form.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#form.style},
+      {<<"tabindex">>, Record#form.tabindex},
+      {<<"title">>, Record#form.title},
+      {<<"translate">>, case Record#form.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"accept-charset">>, Record#form.accept_charset},      
+      {<<"action">>, Record#form.action},      
+      {<<"autocomplete">>, case Record#form.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"enctype">>, case Record#form.enctype of "application/x-www-form-urlencoded" -> "application/x-www-form-urlencoded"; "multipart/form-data" -> "multipart/form-data"; "text/plain" -> "text/plain"; _ -> undefined end},
+      {<<"method">>, case Record#form.method of "post" -> "post"; _ -> "get" end},
+      {<<"name">>,Record#form.name},
+      {<<"novalidate">>, case Record#form.novalidate of true -> "novalidate"; _ -> undefined end},
+      {<<"target">>, Record#form.target} | Record#form.data_fields
+    ],
+    wf_tags:emit_tag(<<"form">>, nitro:render(Record#form.body), List).

+ 31 - 0
src/elements/element_hidden.erl

@@ -0,0 +1,31 @@
+-module(element_hidden).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#hidden.accesskey},
+      {<<"class">>, Record#hidden.class},
+      {<<"contenteditable">>, case Record#hidden.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#hidden.contextmenu},
+      {<<"dir">>, case Record#hidden.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#hidden.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#hidden.dropzone},
+      {<<"hidden">>, case Record#hidden.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#hidden.id},
+      {<<"lang">>, Record#hidden.lang},
+      {<<"spellcheck">>, case Record#hidden.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#hidden.style},
+      {<<"tabindex">>, Record#hidden.tabindex},
+      {<<"title">>, Record#hidden.title},
+      {<<"translate">>, case Record#hidden.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"disabled">>, if Record#hidden.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#hidden.form},
+      {<<"name">>,Record#hidden.name},
+      {<<"type">>, <<"hidden">>},
+      {<<"value">>, nitro:js_escape(Record#hidden.value)} | Record#hidden.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#hidden.body), List).

+ 27 - 0
src/elements/element_html.erl

@@ -0,0 +1,27 @@
+-module(element_html).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#html.accesskey},
+      {<<"class">>, Record#html.class},
+      {<<"contenteditable">>, case Record#html.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#html.contextmenu},
+      {<<"dir">>, case Record#html.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#html.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#html.dropzone},
+      {<<"hidden">>, case Record#html.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#html.id},
+      {<<"lang">>, Record#html.lang},
+      {<<"spellcheck">>, case Record#html.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#html.style},
+      {<<"tabindex">>, Record#html.tabindex},
+      {<<"title">>, Record#html.title},
+      {<<"translate">>, case Record#html.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"manifest">>, Record#html.manifest} | Record#html.data_fields
+    ],
+    wf_tags:emit_tag(<<"html">>, nitro:render(case Record#html.body of undefined -> []; B -> B end), List).

+ 33 - 0
src/elements/element_iframe.erl

@@ -0,0 +1,33 @@
+-module(element_iframe).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#iframe.accesskey},
+      {<<"class">>, Record#iframe.class},
+      {<<"contenteditable">>, case Record#iframe.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#iframe.contextmenu},
+      {<<"dir">>, case Record#iframe.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#iframe.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#iframe.dropzone},
+      {<<"hidden">>, case Record#iframe.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#iframe.id},
+      {<<"lang">>, Record#iframe.lang},
+      {<<"spellcheck">>, case Record#iframe.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#iframe.style},
+      {<<"tabindex">>, Record#iframe.tabindex},
+      {<<"title">>, Record#iframe.title},
+      {<<"translate">>, case Record#iframe.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"height">>,Record#iframe.height},      
+      {<<"sandbox">>,Record#iframe.sandbox},      
+      {<<"seamless">>, if Record#iframe.seamless == true -> "seamless"; true -> undefined end},
+      {<<"src">>,Record#iframe.src},
+      {<<"srcdoc">>,Record#iframe.srcdoc},            
+      {<<"name">>,Record#iframe.name},
+      {<<"width">>,Record#iframe.width} | Record#iframe.data_fields
+    ],
+    wf_tags:emit_tag(<<"iframe">>, [], List).

+ 18 - 0
src/elements/element_image.erl

@@ -0,0 +1,18 @@
+-module(element_image).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+  Attributes = [
+    {<<"id">>, Record#image.id},
+    {<<"class">>, Record#image.class},
+    {<<"title">>, Record#image.title},
+    {<<"style">>, Record#image.style},
+    {<<"alt">>, Record#image.alt},
+    {<<"width">>, Record#image.width},
+    {<<"height">>, Record#image.height},
+    {<<"src">>, nitro:coalesce([Record#image.src, Record#image.image])} | Record#image.data_fields
+  ],
+
+  wf_tags:emit_tag(<<"img">>, Attributes).

+ 48 - 0
src/elements/element_input.erl

@@ -0,0 +1,48 @@
+-module(element_input).
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#input.postback of
+        undefined -> Record#input.id;
+        Postback ->
+          ID = case Record#input.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#input.source, delegate=Record#input.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#input.accesskey},
+      {<<"class">>, Record#input.class},
+      {<<"contenteditable">>, case Record#input.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#input.contextmenu},
+      {<<"dir">>, case Record#input.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#input.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#input.dropzone},
+      {<<"hidden">>, case Record#input.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#input.lang},
+      {<<"spellcheck">>, case Record#input.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#input.style},
+      {<<"tabindex">>, Record#input.tabindex},
+      {<<"title">>, Record#input.title},
+      {<<"translate">>, case Record#input.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,Record#input.autofocus},
+      {<<"disabled">>, if Record#input.disabled == true -> "disabled"; true -> undefined end},
+      {<<"name">>,Record#input.name},
+      {<<"type">>, Record#input.type},
+      {<<"max">>, Record#input.max},
+      {<<"placeholder">>,Record#input.placeholder},
+      {<<"min">>, Record#input.min},
+      {<<"multiple">>, Record#input.multiple },
+      {<<"value">>,      nitro:js_escape(Record#input.value)},
+      {<<"onkeypress">>, nitro:js_escape(Record#input.onkeypress)},
+      {<<"onkeyup">>,    nitro:js_escape(Record#input.onkeyup)},
+      {<<"onkeydown">>,  nitro:js_escape(Record#input.onkeydown)},
+      {<<"onclick">>,    nitro:js_escape(Record#input.onclick)},
+      {<<"onchange">>, Record#input.onchange} | Record#input.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#input.body), List).

+ 40 - 0
src/elements/element_input_button.erl

@@ -0,0 +1,40 @@
+-module(element_input_button).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#input_button.postback of
+        undefined -> Record#input_button.id;
+        Postback ->
+          ID = case Record#input_button.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#input_button.source, delegate=Record#input_button.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#input_button.accesskey},
+      {<<"class">>, Record#input_button.class},
+      {<<"contenteditable">>, case Record#input_button.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#input_button.contextmenu},
+      {<<"dir">>, case Record#input_button.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#input_button.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#input_button.dropzone},
+      {<<"hidden">>, case Record#input_button.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#input_button.lang},
+      {<<"spellcheck">>, case Record#input_button.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#input_button.style},
+      {<<"tabindex">>, Record#input_button.tabindex},
+      {<<"title">>, Record#input_button.title},
+      {<<"translate">>, case Record#input_button.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,Record#input_button.autofocus},
+      {<<"disabled">>, if Record#input_button.disabled == true -> "disabled"; true -> undefined end},
+      {<<"name">>,Record#input_button.name},
+      {<<"type">>, <<"button">>},
+      {<<"value">>,nitro:js_escape(Record#input_button.value)} | Record#input_button.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#input_button.body), List).

+ 49 - 0
src/elements/element_input_image.erl

@@ -0,0 +1,49 @@
+-module(element_input_image).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#input_image.postback of
+        undefined -> Record#input_image.id;
+        Postback ->
+          ID = case Record#input_image.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#input_image.source, delegate=Record#input_image.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#input_image.accesskey},
+      {<<"class">>, Record#input_image.class},
+      {<<"contenteditable">>, case Record#input_image.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#input_image.contextmenu},
+      {<<"dir">>, case Record#input_image.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#input_image.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#input_image.dropzone},
+      {<<"hidden">>, case Record#input_image.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#input_image.lang},
+      {<<"spellcheck">>, case Record#input_image.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#input_image.style},
+      {<<"tabindex">>, Record#input_image.tabindex},
+      {<<"title">>, Record#input_image.title},
+      {<<"translate">>, case Record#input_image.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"alt">>,Record#input_image.alt},
+      {<<"autofocus">>,if Record#input_image.autofocus == true -> "autofocus"; true -> undefined end},      
+      {<<"disabled">>, if Record#input_image.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#input_image.form},
+      {<<"formaction">>,Record#input_image.formaction},
+      {<<"formenctype">>,Record#input_image.formenctype},
+      {<<"formmethod">>,Record#input_image.formmethod},
+      {<<"formnovalue">>,Record#input_image.formnovalue},
+      {<<"formtarget">>,Record#input_image.formtarget},
+      {<<"height">>,Record#input_image.height},
+      {<<"name">>,Record#input_image.name},
+      {<<"src">>,Record#input_image.src},
+      {<<"type">>, <<"image">>},
+      {<<"width">>,Record#input_image.width} | Record#input_image.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#input_image.body), List).

+ 48 - 0
src/elements/element_input_time.erl

@@ -0,0 +1,48 @@
+-module(element_input_time).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#input_time.postback of
+        undefined -> Record#input_time.id;
+        Postback ->
+          ID = case Record#input_time.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#input_time.source, delegate=Record#input_time.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#input_time.accesskey},
+      {<<"class">>, Record#input_time.class},
+      {<<"contenteditable">>, case Record#input_time.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#input_time.contextmenu},
+      {<<"dir">>, case Record#input_time.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#input_time.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#input_time.dropzone},
+      {<<"hidden">>, case Record#input_time.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#input_time.lang},
+      {<<"spellcheck">>, case Record#input_time.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#input_time.style},
+      {<<"tabindex">>, Record#input_time.tabindex},
+      {<<"title">>, Record#input_time.title},
+      {<<"translate">>, case Record#input_time.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#input_time.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#input_time.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#input_time.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#input_time.form},
+      {<<"list">>,Record#input_time.list},
+      {<<"max">>,Record#input_time.max},
+      {<<"min">>,Record#input_time.min},
+      {<<"name">>,Record#input_time.name},
+      {<<"readonly">>,if Record#input_time.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#input_time.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#input_time.step},
+      {<<"type">>, <<"time">>},
+      {<<"value">>,nitro:js_escape(Record#input_time.value)} | Record#input_time.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#input_time.body), List).

+ 28 - 0
src/elements/element_ins.erl

@@ -0,0 +1,28 @@
+-module(element_ins).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#ins.accesskey},
+      {<<"class">>, Record#ins.class},
+      {<<"contenteditable">>, case Record#ins.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#ins.contextmenu},
+      {<<"dir">>, case Record#ins.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#ins.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#ins.dropzone},
+      {<<"hidden">>, case Record#ins.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#ins.id},
+      {<<"lang">>, Record#ins.lang},
+      {<<"spellcheck">>, case Record#ins.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#ins.style},
+      {<<"tabindex">>, Record#ins.tabindex},
+      {<<"title">>, Record#ins.title},
+      {<<"translate">>, case Record#ins.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"cite">>, Record#ins.cite},
+      {<<"datetime">>, Record#ins.datetime} | Record#ins.data_fields
+    ],
+    wf_tags:emit_tag(<<"ins">>, nitro:render(case Record#ins.body of undefined -> []; B -> B end), List).

+ 41 - 0
src/elements/element_keygen.erl

@@ -0,0 +1,41 @@
+-module(element_keygen).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#keygen.postback of
+        undefined -> Record#keygen.id;
+        Postback ->
+          ID = case Record#keygen.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#keygen.source, delegate=Record#keygen.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#keygen.accesskey},
+      {<<"class">>, Record#keygen.class},
+      {<<"contenteditable">>, case Record#keygen.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#keygen.contextmenu},
+      {<<"dir">>, case Record#keygen.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#keygen.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#keygen.dropzone},
+      {<<"hidden">>, case Record#keygen.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#keygen.lang},
+      {<<"spellcheck">>, case Record#keygen.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#keygen.style},
+      {<<"tabindex">>, Record#keygen.tabindex},
+      {<<"title">>, Record#keygen.title},
+      {<<"translate">>, case Record#keygen.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,if Record#keygen.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"challenge">>,Record#keygen.challenge},      
+      {<<"disabled">>, if Record#keygen.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#keygen.form},
+      {<<"keytype">>,<<"rsa">>},
+      {<<"name">>,Record#keygen.name} | Record#keygen.data_fields
+    ],
+    wf_tags:emit_tag(<<"keygen">>, nitro:render(Record#keygen.body), List).

+ 13 - 0
src/elements/element_label.erl

@@ -0,0 +1,13 @@
+-module(element_label).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+  wf_tags:emit_tag(<<"label">>, nitro:render(Record#label.body), [
+    {<<"id">>, Record#label.id},
+    {<<"class">>, Record#label.class},
+    {<<"style">>, Record#label.style},
+    {<<"for">>, Record#label.for},
+    {<<"onclick">>, nitro:js_escape(Record#label.onclick)} | Record#label.data_fields
+  ]).

+ 11 - 0
src/elements/element_legend.erl

@@ -0,0 +1,11 @@
+-module(element_legend).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+  wf_tags:emit_tag(<<"legend">>, nitro:render(Record#legend.body), [
+    {<<"id">>, Record#legend.id},
+    {<<"class">>, Record#legend.class},
+    {<<"style">>, Record#legend.style} | Record#legend.data_fields
+  ]).

+ 11 - 0
src/elements/element_li.erl

@@ -0,0 +1,11 @@
+-module(element_li).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+  wf_tags:emit_tag(<<"li">>, nitro:render(Record#li.body), [
+    {<<"class">>, Record#li.class},
+    {<<"id">>, Record#li.id},
+    {<<"style">>, Record#li.style} | Record#li.data_fields
+  ]).

+ 42 - 0
src/elements/element_link.erl

@@ -0,0 +1,42 @@
+-module(element_link).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+    Id = case Record#link.postback of
+        undefined -> Record#link.id;
+        Postback ->
+            ID = case Record#link.id of undefined -> nitro:temp_id(); I -> I end,
+            nitro:wire(#event{ type=click,postback=Postback,target=ID,
+                            source=Record#link.source,delegate=Record#link.delegate}),
+            ID end,
+    List = [
+      % global
+      {<<"accesskey">>, Record#link.accesskey},
+      {<<"class">>, Record#link.class},
+      {<<"contenteditable">>, case Record#link.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#link.contextmenu},
+      {<<"dir">>, case Record#link.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#link.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#link.dropzone},
+      {<<"hidden">>, case Record#link.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#link.lang},
+      {<<"spellcheck">>, case Record#link.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#link.style},
+      {<<"tabindex">>, Record#link.tabindex},
+      {<<"title">>, Record#link.title},
+      {<<"translate">>, case Record#link.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"href">>, nitro:coalesce([Record#link.href,Record#link.url])},
+      {<<"hreflang">>, Record#link.hreflang},
+      {<<"target">>, Record#link.target},
+      {<<"media">>, Record#link.media},
+      {<<"rel">>, Record#link.rel},
+      {<<"type">>, Record#link.type},
+      {<<"download">>, Record#link.download},
+      {<<"name">>, Record#link.name},
+      {<<"onclick">>, Record#link.onclick},
+      {<<"onmouseover">>, Record#link.onmouseover} | Record#link.data_fields ],
+    wf_tags:emit_tag(<<"a">>, nitro:render(Record#link.body), List).

+ 14 - 0
src/elements/element_list.erl

@@ -0,0 +1,14 @@
+-module(element_list).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record = #list{}) -> 
+  Tag = case Record#list.numbered of true -> <<"ol">>; _ -> <<"ul">> end,
+
+  wf_tags:emit_tag(Tag, nitro:render(Record#list.body), [
+    {<<"id">>, Record#list.id},
+    {<<"class">>, Record#list.class},
+    {<<"style">>, Record#list.style} | Record#list.data_fields
+  ]).
+

+ 6 - 0
src/elements/element_literal.erl

@@ -0,0 +1,6 @@
+-module(element_literal).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> nitro:html_encode(Record#literal.body).

+ 27 - 0
src/elements/element_map.erl

@@ -0,0 +1,27 @@
+-module(element_map).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#map.accesskey},
+      {<<"class">>, Record#map.class},
+      {<<"contenteditable">>, case Record#map.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#map.contextmenu},
+      {<<"dir">>, case Record#map.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#map.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#map.dropzone},
+      {<<"hidden">>, case Record#map.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#map.id},
+      {<<"lang">>, Record#map.lang},
+      {<<"spellcheck">>, case Record#map.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#map.style},
+      {<<"tabindex">>, Record#map.tabindex},
+      {<<"title">>, Record#map.title},
+      {<<"translate">>, case Record#map.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"name">>,Record#map.name} | Record#map.data_fields
+    ],
+    wf_tags:emit_tag(<<"map">>, nitro:render(case Record#map.body of undefined -> []; B -> B end), List).

+ 28 - 0
src/elements/element_menu.erl

@@ -0,0 +1,28 @@
+-module(element_menu).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#menu.accesskey},
+      {<<"class">>, Record#menu.class},
+      {<<"contenteditable">>, case Record#menu.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#menu.contextmenu},
+      {<<"dir">>, case Record#menu.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#menu.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#menu.dropzone},
+      {<<"hidden">>, case Record#menu.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#menu.id},
+      {<<"lang">>, Record#menu.lang},
+      {<<"spellcheck">>, case Record#menu.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#menu.style},
+      {<<"tabindex">>, Record#menu.tabindex},
+      {<<"title">>, Record#menu.title},
+      {<<"translate">>, case Record#menu.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"label">>, Record#menu.label},
+      {<<"type">>, case Record#menu.type of "toolbar" -> "toolbar"; "context" -> "context"; _ -> undefined end} | Record#menu.data_fields
+    ],
+    wf_tags:emit_tag(<<"menu">>, nitro:render(case Record#menu.body of undefined -> []; B -> B end), List).

+ 31 - 0
src/elements/element_meta.erl

@@ -0,0 +1,31 @@
+-module(element_meta).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#meta.accesskey},
+      {<<"class">>, Record#meta.class},
+      {<<"contenteditable">>, case Record#meta.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#meta.contextmenu},
+      {<<"dir">>, case Record#meta.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#meta.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#meta.dropzone},
+      {<<"hidden">>, case Record#meta.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#meta.id},
+      {<<"lang">>, Record#meta.lang},
+      {<<"spellcheck">>, case Record#meta.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#meta.style},
+      {<<"tabindex">>, Record#meta.tabindex},
+      {<<"title">>, Record#meta.title},
+      {<<"translate">>, case Record#meta.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"charset">>, Record#meta.charset},
+      {<<"content">>, Record#meta.content},
+      {<<"http_equiv">>, Record#meta.http_equiv},
+      {<<"name">>, Record#meta.name},
+      {<<"type">>, Record#meta.type} | Record#meta.data_fields
+    ],
+    wf_tags:emit_tag(<<"meta">>, List).

+ 28 - 0
src/elements/element_meta_base.erl

@@ -0,0 +1,28 @@
+-module(element_meta_base).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#base.accesskey},
+      {<<"class">>, Record#base.class},
+      {<<"contenteditable">>, case Record#base.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#base.contextmenu},
+      {<<"dir">>, case Record#base.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#base.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#base.dropzone},
+      {<<"hidden">>, case Record#base.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#base.id},
+      {<<"lang">>, Record#base.lang},
+      {<<"spellcheck">>, case Record#base.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#base.style},
+      {<<"tabindex">>, Record#base.tabindex},
+      {<<"title">>, Record#base.title},
+      {<<"translate">>, case Record#base.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"href">>,Record#base.href},
+      {<<"target">>,Record#base.target} | Record#base.data_fields
+    ],
+    wf_tags:emit_tag(<<"base">>, List).

+ 32 - 0
src/elements/element_meta_link.erl

@@ -0,0 +1,32 @@
+-module(element_meta_link).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#meta_link.accesskey},
+      {<<"class">>, Record#meta_link.class},
+      {<<"contenteditable">>, case Record#meta_link.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#meta_link.contextmenu},
+      {<<"dir">>, case Record#meta_link.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#meta_link.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#meta_link.dropzone},
+      {<<"hidden">>, case Record#meta_link.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#meta_link.id},
+      {<<"lang">>, Record#meta_link.lang},
+      {<<"spellcheck">>, case Record#meta_link.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#meta_link.style},
+      {<<"tabindex">>, Record#meta_link.tabindex},
+      {<<"title">>, Record#meta_link.title},
+      {<<"translate">>, case Record#meta_link.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"href">>,Record#meta_link.href},
+      {<<"hreflang">>,Record#meta_link.hreflang},
+      {<<"media">>,Record#meta_link.media},
+      {<<"rel">>,Record#meta_link.rel},
+      {<<"sizes">>,Record#meta_link.sizes},
+      {<<"type">>,Record#meta_link.type} | Record#meta_link.data_fields
+    ],
+    wf_tags:emit_tag(<<"link">>, List).

+ 32 - 0
src/elements/element_meter.erl

@@ -0,0 +1,32 @@
+-module(element_meter).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#meter.accesskey},
+      {<<"class">>, Record#meter.class},
+      {<<"contenteditable">>, case Record#meter.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#meter.contextmenu},
+      {<<"dir">>, case Record#meter.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#meter.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#meter.dropzone},
+      {<<"hidden">>, case Record#meter.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#meter.id},
+      {<<"lang">>, Record#meter.lang},
+      {<<"spellcheck">>, case Record#meter.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#meter.style},
+      {<<"tabindex">>, Record#meter.tabindex},
+      {<<"title">>, Record#meter.title},
+      {<<"translate">>, case Record#meter.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"high">>,Record#meter.high},
+      {<<"low">>,Record#meter.low},
+      {<<"max">>,Record#meter.max},
+      {<<"min">>,Record#meter.min},
+      {<<"optimum">>,Record#meter.optimum},
+      {<<"value">>, nitro:js_escape(Record#meter.value)} | Record#meter.data_fields
+    ],
+    wf_tags:emit_tag(<<"meter">>, nitro:render(case Record#meter.body of undefined -> []; B -> B end), List).

+ 47 - 0
src/elements/element_month.erl

@@ -0,0 +1,47 @@
+-module(element_month).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#month.postback of
+        undefined -> Record#month.id;
+        Postback ->
+          ID = case Record#month.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#month.source, delegate=Record#month.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#month.accesskey},
+      {<<"class">>, Record#month.class},
+      {<<"contenteditable">>, case Record#month.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#month.contextmenu},
+      {<<"dir">>, case Record#month.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#month.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#month.dropzone},
+      {<<"hidden">>, case Record#month.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#month.lang},
+      {<<"spellcheck">>, case Record#month.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#month.style},
+      {<<"tabindex">>, Record#month.tabindex},
+      {<<"title">>, Record#month.title},
+      {<<"translate">>, case Record#month.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"alt">>,Record#month.alt},
+      {<<"autofocus">>,if Record#month.autofocus == true -> "autofocus"; true -> undefined end},            
+      {<<"disabled">>, if Record#month.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#month.form},
+      {<<"max">>,Record#month.max},
+      {<<"min">>,Record#month.min},      
+      {<<"name">>,Record#month.name},
+      {<<"readonly">>,if Record#month.readonly == true -> "readonly"; true -> undefined end},      
+      {<<"required">>,if Record#month.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#month.step},
+      {<<"type">>, <<"month">>},
+      {<<"value">>,nitro:js_escape(Record#month.value)} | Record#month.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#month.body), List).

+ 49 - 0
src/elements/element_number.erl

@@ -0,0 +1,49 @@
+-module(element_number).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#number.postback of
+        undefined -> Record#number.id;
+        Postback ->
+          ID = case Record#number.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#number.source, delegate=Record#number.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#number.accesskey},
+      {<<"class">>, Record#number.class},
+      {<<"contenteditable">>, case Record#number.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#number.contextmenu},
+      {<<"dir">>, case Record#number.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#number.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#number.dropzone},
+      {<<"hidden">>, case Record#number.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#number.lang},
+      {<<"spellcheck">>, case Record#number.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#number.style},
+      {<<"tabindex">>, Record#number.tabindex},
+      {<<"title">>, Record#number.title},
+      {<<"translate">>, case Record#number.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec      
+      {<<"autocomplete">>, case Record#number.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#number.autofocus == true -> "autofocus"; true -> undefined end},            
+      {<<"disabled">>, if Record#number.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#number.form},
+      {<<"list">>,Record#number.list},
+      {<<"max">>,Record#number.max},
+      {<<"min">>,Record#number.min},      
+      {<<"name">>,Record#number.name},
+      {<<"placeholder">>,Record#number.placeholder},
+      {<<"readonly">>,if Record#number.readonly == true -> "readonly"; true -> undefined end},      
+      {<<"required">>,if Record#number.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#number.step},
+      {<<"type">>, <<"number">>},
+      {<<"value">>,nitro:js_escape(Record#number.value)} | Record#number.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#number.body), List).

+ 33 - 0
src/elements/element_object.erl

@@ -0,0 +1,33 @@
+-module(element_object).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#object.accesskey},
+      {<<"class">>, Record#object.class},
+      {<<"contenteditable">>, case Record#object.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#object.contextmenu},
+      {<<"dir">>, case Record#object.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#object.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#object.dropzone},
+      {<<"hidden">>, case Record#object.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#object.id},
+      {<<"lang">>, Record#object.lang},
+      {<<"spellcheck">>, case Record#object.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#object.style},
+      {<<"tabindex">>, Record#object.tabindex},
+      {<<"title">>, Record#object.title},
+      {<<"translate">>, case Record#object.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"data">>,Record#object.data},      
+      {<<"form">>,Record#object.form},      
+      {<<"height">>,Record#object.height},      
+      {<<"name">>,Record#object.name},            
+      {<<"type">>,Record#object.type},
+      {<<"usemap">>,Record#object.usemap},            
+      {<<"width">>,Record#object.width} | Record#object.data_fields
+    ],
+    wf_tags:emit_tag(<<"object">>, nitro:render(case Record#object.body of undefined -> []; B -> B end), List).

+ 29 - 0
src/elements/element_output.erl

@@ -0,0 +1,29 @@
+-module(element_output).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#output.accesskey},
+      {<<"class">>, Record#output.class},
+      {<<"contenteditable">>, case Record#output.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#output.contextmenu},
+      {<<"dir">>, case Record#output.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#output.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#output.dropzone},
+      {<<"hidden">>, case Record#output.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#output.id},
+      {<<"lang">>, Record#output.lang},
+      {<<"spellcheck">>, case Record#output.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#output.style},
+      {<<"tabindex">>, Record#output.tabindex},
+      {<<"title">>, Record#output.title},
+      {<<"translate">>, case Record#output.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"for">>,Record#output.for},
+      {<<"form">>,Record#output.form},
+      {<<"name">>,Record#output.name} | Record#output.data_fields
+    ],
+    wf_tags:emit_tag(<<"output">>, nitro:render(case Record#output.body of undefined -> []; B -> B end), List).

+ 13 - 0
src/elements/element_panel.erl

@@ -0,0 +1,13 @@
+-module(element_panel).
+-author('Maxim Sokhatsky').
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+  wf_tags:emit_tag(<<"div">>, nitro:render(Record#panel.body),
+    lists:append([
+      [{<<"id">>,   Record#panel.id},
+      {<<"class">>, Record#panel.class},
+      {<<"style">>, Record#panel.style}],
+      Record#panel.data_fields,
+      Record#panel.aria_states])).

+ 28 - 0
src/elements/element_param.erl

@@ -0,0 +1,28 @@
+-module(element_param).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#param.accesskey},
+      {<<"class">>, Record#param.class},
+      {<<"contenteditable">>, case Record#param.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#param.contextmenu},
+      {<<"dir">>, case Record#param.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#param.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#param.dropzone},
+      {<<"hidden">>, case Record#param.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#param.id},
+      {<<"lang">>, Record#param.lang},
+      {<<"spellcheck">>, case Record#param.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#param.style},
+      {<<"tabindex">>, Record#param.tabindex},
+      {<<"title">>, Record#param.title},
+      {<<"translate">>, case Record#param.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"name">>,Record#param.name},
+      {<<"value">>,Record#param.value} | Record#param.data_fields
+    ],
+    wf_tags:emit_tag(<<"param">>, List).

+ 48 - 0
src/elements/element_password.erl

@@ -0,0 +1,48 @@
+-module(element_password).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#password.postback of
+        undefined -> Record#password.id;
+        Postback ->
+          ID = case Record#password.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#password.source, delegate=Record#password.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#password.accesskey},
+      {<<"class">>, Record#password.class},
+      {<<"contenteditable">>, case Record#password.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#password.contextmenu},
+      {<<"dir">>, case Record#password.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#password.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#password.dropzone},
+      {<<"hidden">>, case Record#password.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#password.lang},
+      {<<"spellcheck">>, case Record#password.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#password.style},
+      {<<"tabindex">>, Record#password.tabindex},
+      {<<"title">>, Record#password.title},
+      {<<"translate">>, case Record#password.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec 
+      {<<"autocomplete">>, case Record#password.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},      
+      {<<"autofocus">>,if Record#password.autofocus == true -> "autofocus"; true -> undefined end},            
+      {<<"disabled">>, if Record#password.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#password.form},
+      {<<"maxlength">>,Record#password.maxlength},
+      {<<"name">>,Record#password.name},
+      {<<"pattern">>,Record#password.pattern},
+      {<<"placeholder">>, Record#password.placeholder},
+      {<<"readonly">>,if Record#password.readonly == true -> "readonly"; true -> undefined end},      
+      {<<"required">>,if Record#password.required == true -> "required"; true -> undefined end},      
+      {<<"size">>,Record#password.size},
+      {<<"type">>, <<"password">>},
+      {<<"value">>,nitro:js_escape(Record#password.value)} | Record#password.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#password.body), List).

+ 28 - 0
src/elements/element_progress.erl

@@ -0,0 +1,28 @@
+-module(element_progress).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#progress.accesskey},
+      {<<"class">>, Record#progress.class},
+      {<<"contenteditable">>, case Record#progress.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#progress.contextmenu},
+      {<<"dir">>, case Record#progress.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#progress.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#progress.dropzone},
+      {<<"hidden">>, case Record#progress.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#progress.id},
+      {<<"lang">>, Record#progress.lang},
+      {<<"spellcheck">>, case Record#progress.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#progress.style},
+      {<<"tabindex">>, Record#progress.tabindex},
+      {<<"title">>, Record#progress.title},
+      {<<"translate">>, case Record#progress.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"max">>,Record#progress.max},
+      {<<"value">>,Record#progress.value} | Record#progress.data_fields
+    ],
+    wf_tags:emit_tag(<<"progress">>, nitro:render(case Record#progress.body of undefined -> []; B -> B end), List).

+ 27 - 0
src/elements/element_q.erl

@@ -0,0 +1,27 @@
+-module(element_q).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#q.accesskey},
+      {<<"class">>, Record#q.class},
+      {<<"contenteditable">>, case Record#q.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#q.contextmenu},
+      {<<"dir">>, case Record#q.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#q.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#q.dropzone},
+      {<<"hidden">>, case Record#q.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#q.id},
+      {<<"lang">>, Record#q.lang},
+      {<<"spellcheck">>, case Record#q.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#q.style},
+      {<<"tabindex">>, Record#q.tabindex},
+      {<<"title">>, Record#q.title},
+      {<<"translate">>, case Record#q.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"cite">>,Record#q.cite} | Record#q.data_fields
+    ],
+    wf_tags:emit_tag( <<"q">>, nitro:render(case Record#q.body of undefined -> []; B -> B end), List).

+ 34 - 0
src/elements/element_radio.erl

@@ -0,0 +1,34 @@
+-module(element_radio).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    ID = case Record#radio.id of
+        undefined -> nitro:temp_id();
+        RadioID -> RadioID
+    end,
+
+    case Record#radio.postback of
+        undefined -> ignore;
+        Postback -> nitro:wire(#event{type=change, postback=Postback, target=ID, delegate=Record#radio.delegate })
+    end,
+
+    Content = nitro:render(Record#radio.body),
+    TypeChecked = case Record#radio.checked of
+         true -> [{<<"checked">>, <<"">>},{<<"type">>, <<"radio">>}];
+            _ -> [{<<"type">>, <<"radio">>}] end ++ case Record#radio.disabled of
+         true -> [{<<"disabled">>, <<"disabled">>}];
+            _ -> [] end,
+
+    [
+        wf_tags:emit_tag(<<"input">>, Content, TypeChecked ++ [
+            {<<"id">>, ID},
+            {<<"value">>, Record#radio.value},
+            {<<"name">>, nitro:coalesce([Record#radio.html_name,Record#radio.name])},
+            {<<"class">>, Record#radio.class},
+            {<<"style">>, Record#radio.style},
+            {<<"onclick">>, nitro:js_escape(Record#radio.onclick)}
+        ])
+
+    ].

+ 23 - 0
src/elements/element_radiogroup.erl

@@ -0,0 +1,23 @@
+-module(element_radiogroup).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+    ID = Record#radiogroup.id,
+    Body = apply_name(ID, Record#radiogroup.body),
+    element_panel:render_element(#panel {
+        id=ID,
+        class=[radiogroup, Record#radiogroup.class],
+        style=Record#radiogroup.style,
+        body=Body
+    }).
+
+%% TODO: This whole thing needs to be replaced with a smarter recursive search.
+%% As it is, it won't dive into the bodies of subelements. A recursive map (ie: nitro:map_body) would be
+%% ideal
+
+apply_name(Name, Terms) -> [do_apply(Name, X) || X <- Terms].
+do_apply(Name, X) when is_record(X, radio) -> X#radio {name = Name};
+do_apply(Name, List) when is_list(List) -> apply_name(Name,List);
+do_apply(_Name, X) -> X.

+ 46 - 0
src/elements/element_range.erl

@@ -0,0 +1,46 @@
+-module(element_range).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#range.postback of
+        undefined -> Record#range.id;
+        Postback ->
+          ID = case Record#range.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#range.source, delegate=Record#range.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#range.accesskey},
+      {<<"class">>, Record#range.class},
+      {<<"contenteditable">>, case Record#range.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#range.contextmenu},
+      {<<"dir">>, case Record#range.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#range.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#range.dropzone},
+      {<<"hidden">>, case Record#range.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#range.lang},
+      {<<"spellcheck">>, case Record#range.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#range.style},
+      {<<"tabindex">>, Record#range.tabindex},
+      {<<"title">>, Record#range.title},
+      {<<"translate">>, case Record#range.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#range.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#range.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#range.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#range.form},
+      {<<"list">>,Record#range.list},
+      {<<"max">>,Record#range.max},
+      {<<"min">>,Record#range.min},
+      {<<"name">>,Record#range.name},
+      {<<"step">>,Record#range.step},
+      {<<"type">>, <<"range">>},
+      {<<"value">>, nitro:js_escape(Record#range.value)} | Record#range.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#range.body), List).

+ 41 - 0
src/elements/element_reset.erl

@@ -0,0 +1,41 @@
+-module(element_reset).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#reset.postback of
+        undefined -> Record#reset.id;
+        Postback ->
+          ID = case Record#reset.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#reset.source, delegate=Record#reset.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#reset.accesskey},
+      {<<"class">>, Record#reset.class},
+      {<<"contenteditable">>, case Record#reset.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#reset.contextmenu},
+      {<<"dir">>, case Record#reset.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#reset.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#reset.dropzone},
+      {<<"hidden">>, case Record#reset.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#reset.lang},
+      {<<"spellcheck">>, case Record#reset.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#reset.style},
+      {<<"tabindex">>, Record#reset.tabindex},
+      {<<"title">>, Record#reset.title},
+      {<<"translate">>, case Record#reset.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,if Record#reset.autofocus == true -> "autofocus"; true -> undefined end},            
+      {<<"disabled">>, if Record#reset.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#reset.form},
+      {<<"name">>,Record#reset.name},
+      {<<"type">>, <<"reset">>},
+      {<<"value">>, nitro:js_escape(Record#reset.value)} | Record#reset.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#reset.body), List).

+ 31 - 0
src/elements/element_script.erl

@@ -0,0 +1,31 @@
+-module(element_script).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#script.accesskey},
+      {<<"class">>, Record#script.class},
+      {<<"contenteditable">>, case Record#script.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#script.contextmenu},
+      {<<"dir">>, case Record#script.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#script.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#script.dropzone},
+      {<<"hidden">>, case Record#script.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#script.id},
+      {<<"lang">>, Record#script.lang},
+      {<<"spellcheck">>, case Record#script.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#script.style},
+      {<<"tabindex">>, Record#script.tabindex},
+      {<<"title">>, Record#script.title},
+      {<<"translate">>, case Record#script.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"async">>, if Record#script.async == true -> "async"; true -> undefined end},
+      {<<"charset">>,Record#script.charset},
+      {<<"defer">>, if Record#script.defer == true -> "defer"; true -> undefined end},
+      {<<"src">>,Record#script.src},
+      {<<"type">>,Record#script.type} | Record#script.data_fields
+    ],
+    wf_tags:emit_tag(<<"script">>, nitro:render(case Record#script.body of undefined -> []; B -> B end), List).

+ 50 - 0
src/elements/element_search.erl

@@ -0,0 +1,50 @@
+-module(element_search).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#search.postback of
+        undefined -> Record#search.id;
+        Postback ->
+          ID = case Record#search.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#search.source, delegate=Record#search.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#search.accesskey},
+      {<<"class">>, Record#search.class},
+      {<<"contenteditable">>, case Record#search.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#search.contextmenu},
+      {<<"dir">>, case Record#search.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#search.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#search.dropzone},
+      {<<"hidden">>, case Record#search.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#search.lang},
+      {<<"spellcheck">>, case Record#search.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#search.style},
+      {<<"tabindex">>, Record#search.tabindex},
+      {<<"title">>, Record#search.title},
+      {<<"translate">>, case Record#search.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#search.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#search.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"dirname">>,Record#search.dirname},
+      {<<"disabled">>, if Record#search.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#search.form},
+      {<<"list">>,Record#search.list},
+      {<<"maxlength">>,Record#search.maxlength},
+      {<<"name">>,Record#search.name},
+      {<<"pattern">>,Record#search.pattern},
+      {<<"placeholder">>,Record#search.placeholder},
+      {<<"readonly">>,if Record#search.readonly == true -> "readonly"; true -> undefined end},      
+      {<<"required">>,if Record#search.required == true -> "required"; true -> undefined end},      
+      {<<"size">>,Record#search.size},
+      {<<"type">>, <<"search">>},
+      {<<"value">>, nitro:js_escape(Record#search.value)} | Record#search.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#search.body), List).

+ 37 - 0
src/elements/element_select.erl

@@ -0,0 +1,37 @@
+-module(element_select).
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record = #select{}) ->
+  ID = case Record#select.id of undefined -> nitro:temp_id(); I->I end,
+  case Record#select.postback of
+    undefined -> skip;
+    Postback -> nitro:wire(#event{ type=change,
+                                target=ID,
+                                postback=Postback,
+                                source=[nitro:to_atom(ID)],
+                                delegate=Record#select.delegate }) end,
+  Props = [
+    {<<"id">>, Record#select.id},
+    {<<"class">>, Record#select.class},
+    {<<"style">>, Record#select.style},
+    {<<"name">>, Record#select.name},
+    {<<"title">>, Record#select.title},
+    {<<"disabled">>, case Record#select.disabled of true -> <<"disabled">>; _-> undefined end},
+    {<<"multiple">>, case Record#select.multiple of true -> <<"multiple">>; _-> undefined end} | Record#select.data_fields
+  ],
+  wf_tags:emit_tag(<<"select">>, nitro:render(Record#select.body),
+                                  Props);
+render_element(Group = #optgroup{}) ->
+  wf_tags:emit_tag(<<"optgroup">>, nitro:render(Group#optgroup.body), [
+    {<<"disabled">>, case Group#optgroup.disabled of true-> <<"disabled">>; _-> undefined end},
+    {<<"label">>, Group#optgroup.label}
+  ]);
+render_element(O = #option{}) ->
+  wf_tags:emit_tag(<<"option">>, nitro:render(O#option.body), [
+    {<<"id">>, O#option.id},
+    {<<"disabled">>, O#option.disabled},
+    {<<"label">>, O#option.label},
+    {<<"title">>, O#option.title},
+    {<<"selected">>, case O#option.selected of true -> <<"selected">>; _-> undefined end},
+    {<<"value">>, O#option.value} | O#option.data_fields]).

+ 29 - 0
src/elements/element_source.erl

@@ -0,0 +1,29 @@
+-module(element_source).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#source.accesskey},
+      {<<"class">>, Record#source.class},
+      {<<"contenteditable">>, case Record#source.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#source.contextmenu},
+      {<<"dir">>, case Record#source.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#source.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#source.dropzone},
+      {<<"hidden">>, case Record#source.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#source.id},
+      {<<"lang">>, Record#source.lang},
+      {<<"spellcheck">>, case Record#source.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#source.style},
+      {<<"tabindex">>, Record#source.tabindex},
+      {<<"title">>, Record#source.title},
+      {<<"translate">>, case Record#source.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"media">>,Record#source.media},
+      {<<"type">>,Record#source.type},
+      {<<"src">>,Record#source.src} | Record#source.data_fields
+    ],
+    wf_tags:emit_tag(<<"source">>, List).

+ 29 - 0
src/elements/element_style.erl

@@ -0,0 +1,29 @@
+-module(element_style).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#style.accesskey},
+      {<<"class">>, Record#style.class},
+      {<<"contenteditable">>, case Record#style.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#style.contextmenu},
+      {<<"dir">>, case Record#style.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#style.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#style.dropzone},
+      {<<"hidden">>, case Record#style.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#style.id},
+      {<<"lang">>, Record#style.lang},
+      {<<"spellcheck">>, case Record#style.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#style.style},
+      {<<"tabindex">>, Record#style.tabindex},
+      {<<"title">>, Record#style.title},
+      {<<"translate">>, case Record#style.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"media">>, Record#style.media},
+      {<<"scoped">>, case Record#style.scoped of true -> "scoped"; _ -> undefined end},      
+      {<<"type">>, Record#style.type} | Record#style.data_fields
+    ],
+    wf_tags:emit_tag(<<"style">>, nitro:render(case Record#style.body of undefined -> []; B -> B end), List).

+ 23 - 0
src/elements/element_submit.erl

@@ -0,0 +1,23 @@
+-module (element_submit).
+-author('Andrew Zadorozhny').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    ID = case Record#submit.id of undefined -> nitro:temp_id(); I->I end,
+    case Record#submit.postback of
+         undefined -> skip;
+         Postback -> nitro:wire(#event { type=click, 
+                                      target=ID,
+                                      postback=Postback,
+                                      source=Record#submit.source }) end,
+    case Record#submit.click of
+         undefined -> ignore;
+         ClickActions -> nitro:wire(#event { target=ID, type=click, actions=ClickActions }) end,
+  wf_tags:emit_tag(<<"input">>, [
+      {<<"id">>, ID},
+      {<<"type">>, <<"submit">>},
+      {<<"class">>, Record#submit.class},
+      {<<"style">>, Record#submit.style},
+      {<<"value">>, Record#submit.body}  | Record#submit.data_fields
+  ]).

+ 25 - 0
src/elements/element_summary.erl

@@ -0,0 +1,25 @@
+-module(element_summary).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#summary.accesskey},
+      {<<"class">>, Record#summary.class},
+      {<<"contenteditable">>, case Record#summary.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#summary.contextmenu},
+      {<<"dir">>, case Record#summary.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#summary.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#summary.dropzone},
+      {<<"hidden">>, case Record#summary.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#summary.id},
+      {<<"lang">>, Record#summary.lang},
+      {<<"spellcheck">>, case Record#summary.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#summary.style},
+      {<<"tabindex">>, Record#summary.tabindex},
+      {<<"title">>, Record#summary.title},
+      {<<"translate">>, case Record#summary.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end} | Record#summary.data_fields
+    ],
+    wf_tags:emit_tag(<<"summary">>, nitro:render(case Record#summary.body of undefined -> []; B -> B end), List).

+ 33 - 0
src/elements/element_table.erl

@@ -0,0 +1,33 @@
+-module(element_table).
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record = #table{}) -> 
+  Header = case Record#table.header of
+    undefined -> "";
+    H when is_tuple(H) -> H;
+    _ -> wf_tags:emit_tag(<<"thead">>, nitro:render(Record#table.header), [])
+  end,
+  Footer = case Record#table.footer of
+    undefined -> "";
+    _ -> wf_tags:emit_tag(<<"tfoot">>, nitro:render(Record#table.footer), [])
+  end,
+  Bodies = case Record#table.body of
+    #tbody{} = B -> B;
+    undefined -> #tbody{};
+    [] -> #tbody{};
+    Rows -> [case B of #tbody{}=B1 -> B1; _-> #tbody{body=B} end  || B <- Rows]
+  end,
+  Caption = case Record#table.caption of
+    undefined -> "";
+    _ -> wf_tags:emit_tag(<<"caption">>, nitro:render(Record#table.caption), [])
+  end,
+  Colgroup = case Record#table.colgroup of
+    undefined -> "";
+    _ -> wf_tags:emit_tag(<<"colgroup">>, nitro:render(Record#table.colgroup), [])
+  end,
+  wf_tags:emit_tag( <<"table">>, nitro:render([Caption, Colgroup, Header, Footer, Bodies]), [
+      {<<"id">>, Record#table.id},
+      {<<"class">>, Record#table.class},
+      {<<"style">>, Record#table.style} | Record#table.data_fields
+  ]).

+ 13 - 0
src/elements/element_td.erl

@@ -0,0 +1,13 @@
+-module(element_td).
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+  wf_tags:emit_tag(<<"td">>, nitro:render(Record#td.body), [
+    {<<"id">>, Record#td.id},
+    {<<"class">>, Record#td.class},
+    {<<"style">>, Record#td.style},
+    {<<"rowspan">>, Record#td.rowspan},
+    {<<"colspan">>, Record#td.colspan},
+    {<<"scope">>, Record#td.scope} | Record#td.data_fields
+  ]).

+ 49 - 0
src/elements/element_tel.erl

@@ -0,0 +1,49 @@
+-module(element_tel).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#tel.postback of
+        undefined -> Record#tel.id;
+        Postback ->
+          ID = case Record#tel.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#tel.source, delegate=Record#tel.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#tel.accesskey},
+      {<<"class">>, Record#tel.class},
+      {<<"contenteditable">>, case Record#tel.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#tel.contextmenu},
+      {<<"dir">>, case Record#tel.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#tel.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#tel.dropzone},
+      {<<"hidden">>, case Record#tel.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#tel.lang},
+      {<<"spellcheck">>, case Record#tel.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#tel.style},
+      {<<"tabindex">>, Record#tel.tabindex},
+      {<<"title">>, Record#tel.title},
+      {<<"translate">>, case Record#tel.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#tel.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#tel.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#tel.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#tel.form},
+      {<<"list">>,Record#tel.list},
+      {<<"maxlength">>,Record#tel.maxlength},
+      {<<"name">>,Record#tel.name},
+      {<<"pattern">>,Record#tel.pattern},
+      {<<"placeholder">>,Record#tel.placeholder},
+      {<<"readonly">>,if Record#tel.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#tel.required == true -> "required"; true -> undefined end},      
+      {<<"size">>,Record#tel.size},
+      {<<"type">>, <<"tel">>},
+      {<<"value">>,nitro:js_escape(Record#tel.value)} | Record#tel.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#tel.body), List).

+ 40 - 0
src/elements/element_textarea.erl

@@ -0,0 +1,40 @@
+-module(element_textarea).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#textarea.accesskey},
+      {<<"class">>, Record#textarea.class},
+      {<<"contenteditable">>, case Record#textarea.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#textarea.contextmenu},
+      {<<"dir">>, case Record#textarea.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#textarea.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#textarea.dropzone},
+      {<<"hidden">>, case Record#textarea.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#textarea.id},
+      {<<"lang">>, Record#textarea.lang},
+      {<<"spellcheck">>, case Record#textarea.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#textarea.style},
+      {<<"tabindex">>, Record#textarea.tabindex},
+      {<<"title">>, Record#textarea.title},
+      {<<"translate">>, case Record#textarea.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autofocus">>,if Record#textarea.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"cols">>,Record#textarea.cols},
+      {<<"dirname">>,Record#textarea.dirname},      
+      {<<"disabled">>, if Record#textarea.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#textarea.form},
+      {<<"maxlength">>,Record#textarea.maxlength},      
+      {<<"name">>,Record#textarea.name},
+      {<<"placeholder">>,Record#textarea.placeholder},
+      {<<"readonly">>,if Record#textarea.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#textarea.required == true -> "required"; true -> undefined end},
+      {<<"rows">>,Record#textarea.rows},      
+      {<<"form">>,Record#textarea.wrap},
+      {<<"value">>,Record#textarea.value},
+      {<<"wrap">>, case Record#textarea.wrap of "hard" -> "hard"; "soft" -> "soft"; _ -> undefined end} | Record#textarea.data_fields
+    ],
+    wf_tags:emit_tag(<<"textarea">>, nitro:render(case Record#textarea.body of undefined -> []; B -> B end), List).

+ 20 - 0
src/elements/element_textbox.erl

@@ -0,0 +1,20 @@
+-module(element_textbox).
+-author('Rusty Klophaus').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) -> 
+    List = [
+      {<<"id">>, Record#textbox.id},
+      {<<"type">>, <<"text">>},
+      {<<"maxlength">>,Record#textbox.maxlength},
+      {<<"style">>,Record#textbox.style},
+      {<<"name">>,Record#textbox.name},
+      {<<"placeholder">>,Record#textbox.placeholder},
+      {<<"value">>,nitro:js_escape(Record#textbox.value)},
+      {<<"disabled">>,Record#textbox.disabled},
+      {<<"autofocus">>,Record#textbox.autofocus},
+      {<<"class">>,Record#textbox.class} | Record#textbox.data_fields
+  ] ++ case Record#textbox.disabled of undefined -> []; _ -> [{<<"disabled">>,<<"disabled">>}] end,
+  wf_tags:emit_tag(<<"input">>, nitro:render(Record#textbox.body), List).
+

+ 13 - 0
src/elements/element_th.erl

@@ -0,0 +1,13 @@
+-module(element_th).
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+  wf_tags:emit_tag(<<"th">>, nitro:render(Record#th.body), [
+    {<<"id">>, Record#th.id},
+    {<<"class">>, Record#th.class},
+    {<<"style">>, Record#th.style},
+    {<<"rowspan">>, Record#th.rowspan},
+    {<<"colspan">>, Record#th.colspan},
+    {<<"scope">>, Record#th.scope} | Record#th.data_fields
+  ]).

+ 27 - 0
src/elements/element_time.erl

@@ -0,0 +1,27 @@
+-module(element_time).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#time.accesskey},
+      {<<"class">>, Record#time.class},
+      {<<"contenteditable">>, case Record#time.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#time.contextmenu},
+      {<<"dir">>, case Record#time.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#time.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#time.dropzone},
+      {<<"hidden">>, case Record#time.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#time.id},
+      {<<"lang">>, Record#time.lang},
+      {<<"spellcheck">>, case Record#time.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#time.style},
+      {<<"tabindex">>, Record#time.tabindex},
+      {<<"title">>, Record#time.title},
+      {<<"translate">>, case Record#time.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"datetime">>,Record#time.datetime} | Record#time.data_fields
+    ],
+    wf_tags:emit_tag(<<"time">>, nitro:render(Record#time.body), List).

+ 14 - 0
src/elements/element_tr.erl

@@ -0,0 +1,14 @@
+-module(element_tr).
+-include("nitro.hrl").
+-compile(export_all).
+
+render_element(Record = #tr{postback= Postback}) ->
+  Id = case Record#tr.id of undefined -> nitro:temp_id(); I->I end,
+  Cursor = case Postback of undefined -> "";
+    P -> nitro:wire(#event {type=click, postback=P, target=Id, delegate=Record#tr.delegate}), "cursor:pointer;"
+  end,
+  wf_tags:emit_tag(<<"tr">>, nitro:render(Record#tr.cells), [
+    {<<"id">>, Record#tr.id},
+    {<<"class">>, Record#tr.class},
+    {<<"style">>, [Record#tr.style, Cursor]} | Record#tr.data_fields
+  ]).

+ 31 - 0
src/elements/element_track.erl

@@ -0,0 +1,31 @@
+-module(element_track).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#track.accesskey},
+      {<<"class">>, Record#track.class},
+      {<<"contenteditable">>, case Record#track.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#track.contextmenu},
+      {<<"dir">>, case Record#track.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#track.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#track.dropzone},
+      {<<"hidden">>, case Record#track.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#track.id},
+      {<<"lang">>, Record#track.lang},
+      {<<"spellcheck">>, case Record#track.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#track.style},
+      {<<"tabindex">>, Record#track.tabindex},
+      {<<"title">>, Record#track.title},
+      {<<"translate">>, case Record#track.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"default">>, case Record#track.default of true -> "default"; _ -> undefined end},
+      {<<"kind">>, case Record#track.kind of "subtitles" -> "subtitles"; "captions" -> "captions"; "descriptions" -> "descriptions"; "chapters" -> "chapters"; "metadata" -> "metadata"; _ -> undefined end},
+      {<<"label">>, Record#track.label},
+      {<<"src">>, Record#track.src},
+      {<<"srclang">>, Record#track.srclang} | Record#track.data_fields
+    ],
+    wf_tags:emit_tag(<<"track">>, List).

+ 49 - 0
src/elements/element_url.erl

@@ -0,0 +1,49 @@
+-module(element_url).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#url.postback of
+        undefined -> Record#url.id;
+        Postback ->
+          ID = case Record#url.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#url.source, delegate=Record#url.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#url.accesskey},
+      {<<"class">>, Record#url.class},
+      {<<"contenteditable">>, case Record#url.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#url.contextmenu},
+      {<<"dir">>, case Record#url.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#url.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#url.dropzone},
+      {<<"hidden">>, case Record#url.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#url.lang},
+      {<<"spellcheck">>, case Record#url.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#url.style},
+      {<<"tabindex">>, Record#url.tabindex},
+      {<<"title">>, Record#url.title},
+      {<<"translate">>, case Record#url.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#url.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#url.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#url.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#url.form},
+      {<<"list">>,Record#url.list},
+      {<<"maxlength">>,Record#url.maxlength},
+      {<<"name">>,Record#url.name},
+      {<<"pattern">>,Record#url.pattern},      
+      {<<"placeholder">>,Record#url.placeholder},      
+      {<<"readonly">>,if Record#url.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#url.required == true -> "required"; true -> undefined end},      
+      {<<"size">>,Record#url.size},
+      {<<"type">>, <<"url">>},
+      {<<"value">>,nitro:js_escape(Record#url.value)} | Record#url.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#url.body), List).

+ 36 - 0
src/elements/element_video.erl

@@ -0,0 +1,36 @@
+-module(element_video).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    List = [
+      %global
+      {<<"accesskey">>, Record#video.accesskey},
+      {<<"class">>, Record#video.class},
+      {<<"contenteditable">>, case Record#video.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#video.contextmenu},
+      {<<"dir">>, case Record#video.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#video.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#video.dropzone},
+      {<<"hidden">>, case Record#video.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Record#video.id},
+      {<<"lang">>, Record#video.lang},
+      {<<"spellcheck">>, case Record#video.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#video.style},
+      {<<"tabindex">>, Record#video.tabindex},
+      {<<"title">>, Record#video.title},
+      {<<"translate">>, case Record#video.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autoplay">>, case Record#video.autoplay of true -> "autoplay"; _ -> undefined end},      
+      {<<"controls">>, case Record#video.controls of true -> "controls"; _ -> undefined end},      
+      {<<"height">>, Record#video.height},      
+      {<<"loop">>, case Record#video.loop of true -> "loop"; _ -> undefined end},            
+      {<<"mediagroup">>, Record#video.mediagroup},      
+      {<<"muted">>, case Record#video.muted of true -> "muted"; _ -> undefined end},
+      {<<"poster">>, Record#video.poster},      
+      {<<"preload">>, case Record#video.preload of "auto" -> "auto"; "none" -> "none"; "metadata" -> "metadata"; _ -> undefined end},
+      {<<"src">>, Record#video.src},     
+      {<<"width">>, Record#video.width} | Record#video.data_fields
+    ],
+    wf_tags:emit_tag(<<"video">>, nitro:render(case Record#video.body of undefined -> []; B -> B end), List).

+ 48 - 0
src/elements/element_week.erl

@@ -0,0 +1,48 @@
+-module(element_week).
+-author('Vladimir Galunshchikov').
+-include_lib("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(Record) ->
+    Id = case Record#week.postback of
+        undefined -> Record#week.id;
+        Postback ->
+          ID = case Record#week.id of
+            undefined -> nitro:temp_id();
+            I -> I end,
+          nitro:wire(#event{type=click, postback=Postback, target=ID,
+                  source=Record#week.source, delegate=Record#week.delegate }),
+          ID end,
+    List = [
+      %global
+      {<<"accesskey">>, Record#week.accesskey},
+      {<<"class">>, Record#week.class},
+      {<<"contenteditable">>, case Record#week.contenteditable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"contextmenu">>, Record#week.contextmenu},
+      {<<"dir">>, case Record#week.dir of "ltr" -> "ltr"; "rtl" -> "rtl"; "auto" -> "auto"; _ -> undefined end},
+      {<<"draggable">>, case Record#week.draggable of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"dropzone">>, Record#week.dropzone},
+      {<<"hidden">>, case Record#week.hidden of "hidden" -> "hidden"; _ -> undefined end},
+      {<<"id">>, Id},
+      {<<"lang">>, Record#week.lang},
+      {<<"spellcheck">>, case Record#week.spellcheck of true -> "true"; false -> "false"; _ -> undefined end},
+      {<<"style">>, Record#week.style},
+      {<<"tabindex">>, Record#week.tabindex},
+      {<<"title">>, Record#week.title},
+      {<<"translate">>, case Record#week.contenteditable of "yes" -> "yes"; "no" -> "no"; _ -> undefined end},      
+      % spec
+      {<<"autocomplete">>, case Record#week.autocomplete of true -> "on"; false -> "off"; _ -> undefined end},
+      {<<"autofocus">>,if Record#week.autofocus == true -> "autofocus"; true -> undefined end},
+      {<<"disabled">>, if Record#week.disabled == true -> "disabled"; true -> undefined end},
+      {<<"form">>,Record#week.form},
+      {<<"list">>,Record#week.list},
+      {<<"max">>,Record#week.max},
+      {<<"min">>,Record#week.min},
+      {<<"name">>,Record#week.name},
+      {<<"readonly">>,if Record#week.readonly == true -> "readonly"; true -> undefined end},
+      {<<"required">>,if Record#week.required == true -> "required"; true -> undefined end},      
+      {<<"step">>,Record#week.step},
+      {<<"type">>, <<"week">>},
+      {<<"value">>,nitro:js_escape(Record#week.value)} | Record#week.data_fields
+    ],
+    wf_tags:emit_tag(<<"input">>, nitro:render(Record#week.body), List).

+ 99 - 0
src/nitro.erl

@@ -0,0 +1,99 @@
+-module(nitro).
+-compile(export_all).
+
+f(S) -> f(S, []).
+f(S, Args) -> lists:flatten(io_lib:format(S, Args)).
+
+coalesce([]) -> undefined;
+coalesce([H]) -> H;
+coalesce([undefined|T]) -> coalesce(T);
+coalesce([[]|T]) -> coalesce(T);
+coalesce([H|_]) -> H.
+
+js_escape(undefined) -> [];
+js_escape(Value) when is_list(Value) -> binary_to_list(js_escape(iolist_to_binary(Value)));
+js_escape(Value) -> js_escape(Value, <<>>).
+js_escape(<<"\\", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\\\">>);
+js_escape(<<"\r", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\r">>);
+js_escape(<<"\n", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\n">>);
+js_escape(<<"\"", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\\"">>);
+js_escape(<<"'",Rest/binary>>,Acc) -> js_escape(Rest, <<Acc/binary, "\\'">>);
+js_escape(<<"<script", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "<scr\" + \"ipt">>);
+js_escape(<<"script>", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "scr\" + \"ipt>">>);
+js_escape(<<C, Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, C>>);
+js_escape(<<>>, Acc) -> Acc.
+
+to_binary(A) when is_atom(A) -> atom_to_binary(A,latin1);
+to_binary(B) when is_binary(B) -> B;
+to_binary(I) when is_integer(I) -> to_binary(integer_to_list(I));
+to_binary(F) when is_float(F) -> to_binary(nitro_mochinum:digits(F));
+to_binary(L) when is_list(L) ->  iolist_to_binary(L). % unicode:characters_to_binary(L).
+
+-define(IS_STRING(Term), (is_list(Term) andalso Term /= [] andalso is_integer(hd(Term)))).
+
+to_list(L) when ?IS_STRING(L) -> L;
+to_list(L) when is_list(L) -> SubLists = [inner_to_list(X) || X <- L], lists:flatten(SubLists);
+to_list(A) -> inner_to_list(A).
+
+inner_to_list(A) when is_atom(A) -> atom_to_list(A);
+inner_to_list(B) when is_binary(B) -> binary_to_list(B);
+inner_to_list(I) when is_integer(I) -> integer_to_list(I);
+inner_to_list(L) when is_tuple(L) -> lists:flatten(io_lib:format("~p", [L]));
+inner_to_list(L) when is_list(L) -> L;
+inner_to_list(F) when is_float(F) ->
+    case F == round(F) of
+        true -> inner_to_list(round(F));
+        false -> nitro_mochinum:digits(F) end.
+
+
+-ifndef(PICKLER).
+-define(PICKLER, (application:get_env(n2o,pickler,nitro_pickle))).
+-endif.
+
+pickle(Data) -> ?PICKLER:pickle(Data).
+depickle(SerializedData) -> ?PICKLER:depickle(SerializedData).
+depickle(SerializedData, TTLSeconds) -> ?PICKLER:depickle(SerializedData, TTLSeconds).
+
+render(X) -> wf_render:render(X).
+wire(Actions) -> action_wire:wire(Actions).
+
+temp_id() -> {_, _, C} = now(), "auto" ++ integer_to_list(C).
+
+html_encode(L,Fun) when is_function(Fun) -> Fun(L);
+html_encode(L,EncType) when is_atom(L) -> html_encode(nitro:to_list(L),EncType);
+html_encode(L,EncType) when is_integer(L) -> html_encode(integer_to_list(L),EncType);
+html_encode(L,EncType) when is_float(L) -> html_encode(nitro_mochinum:digits(L),EncType);
+html_encode(L, false) -> L; %wf:to_list(lists:flatten([L]));
+html_encode(L, true) -> L; %html_encode(wf:to_list(lists:flatten([L])));
+html_encode(L, whites) -> html_encode_whites(nitro:to_list(lists:flatten([L]))).
+html_encode(<<>>) -> [];
+html_encode([]) -> [];
+html_encode([H|T]) ->
+	case H of
+		$< -> "&lt;" ++ html_encode(T);
+		$> -> "&gt;" ++ html_encode(T);
+		$" -> "&quot;" ++ html_encode(T);
+		$' -> "&#39;" ++ html_encode(T);
+		$& -> "&amp;" ++ html_encode(T);
+		BigNum when is_integer(BigNum) andalso BigNum > 255 ->
+			%% Any integers above 255 are converted to their HTML encode equivilant,
+			%% Example: 7534 gets turned into &#7534;
+			[$&,$# | nitro:to_list(BigNum)] ++ ";" ++ html_encode(T);
+		Tup when is_tuple(Tup) ->
+			throw({html_encode,encountered_tuple,Tup});
+		_ -> [H|html_encode(T)]
+	end.
+
+html_encode_whites([]) -> [];
+html_encode_whites([H|T]) ->
+	case H of
+		$\s -> "&nbsp;" ++ html_encode_whites(T);
+		$\t -> "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" ++ html_encode_whites(T);
+		$< -> "&lt;" ++ html_encode_whites(T);
+		$> -> "&gt;" ++ html_encode_whites(T);
+		$" -> "&quot;" ++ html_encode_whites(T);
+		$' -> "&#39;" ++ html_encode_whites(T);
+		$& -> "&amp;" ++ html_encode_whites(T);
+		$\n -> "<br>" ++ html_encode_whites(T);
+		_ -> [H|html_encode_whites(T)]
+	end.

+ 186 - 0
src/nitro_mochinum.erl

@@ -0,0 +1,186 @@
+-module(nitro_mochinum).
+-author('Bob Ippolito').
+-compile(export_all).
+
+%% IEEE 754 Float exponent bias
+-define(FLOAT_BIAS, 1022).
+-define(MIN_EXP, -1074).
+-define(BIG_POW, 4503599627370496).
+
+digits(N) when is_integer(N) -> integer_to_list(N);
+digits(0.0) -> "0.0";
+digits(Float) ->
+    {Frac1, Exp1} = frexp_int(Float),
+    [Place0 | Digits0] = digits1(Float, Exp1, Frac1),
+    {Place, Digits} = transform_digits(Place0, Digits0),
+    R = insert_decimal(Place, Digits),
+    case Float < 0 of
+        true ->
+            [$- | R];
+        _ ->
+            R
+    end.
+
+frexp(F) -> frexp1(unpack(F)).
+
+int_pow(_X, 0) -> 1;
+int_pow(X, N) when N > 0 -> int_pow(X, N, 1).
+int_ceil(X) -> T = trunc(X), case (X - T) of Pos when Pos > 0 -> T + 1; _ -> T end.
+int_pow(X, N, R) when N < 2 -> R * X;
+int_pow(X, N, R) -> int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end).
+
+insert_decimal(0, S) -> "0." ++ S;
+insert_decimal(Place, S) when Place > 0 ->
+    L = length(S),
+    case Place - L of
+         0 ->
+            S ++ ".0";
+        N when N < 0 ->
+            {S0, S1} = lists:split(L + N, S),
+            S0 ++ "." ++ S1;
+        N when N < 6 ->
+            %% More places than digits
+            S ++ lists:duplicate(N, $0) ++ ".0";
+        _ ->
+            insert_decimal_exp(Place, S)
+    end;
+insert_decimal(Place, S) when Place > -6 -> "0." ++ lists:duplicate(abs(Place), $0) ++ S;
+insert_decimal(Place, S) -> insert_decimal_exp(Place, S).
+
+insert_decimal_exp(Place, S) ->
+    [C | S0] = S,
+    S1 = case S0 of
+             [] ->
+                 "0";
+             _ ->
+                 S0
+         end,
+    Exp = case Place < 0 of
+              true ->
+                  "e-";
+              false ->
+                  "e+"
+          end,
+    [C] ++ "." ++ S1 ++ Exp ++ integer_to_list(abs(Place - 1)).
+
+
+digits1(Float, Exp, Frac) ->
+    Round = ((Frac band 1) =:= 0),
+    case Exp >= 0 of
+        true ->
+            BExp = 1 bsl Exp,
+            case (Frac =/= ?BIG_POW) of
+                true ->
+                    scale((Frac * BExp * 2), 2, BExp, BExp,
+                          Round, Round, Float);
+                false ->
+                    scale((Frac * BExp * 4), 4, (BExp * 2), BExp,
+                          Round, Round, Float)
+            end;
+        false ->
+            case (Exp =:= ?MIN_EXP) orelse (Frac =/= ?BIG_POW) of
+                true ->
+                    scale((Frac * 2), 1 bsl (1 - Exp), 1, 1,
+                          Round, Round, Float);
+                false ->
+                    scale((Frac * 4), 1 bsl (2 - Exp), 2, 1,
+                          Round, Round, Float)
+            end
+    end.
+
+scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) ->
+    Est = int_ceil(math:log10(abs(Float)) - 1.0e-10),
+    %% Note that the scheme implementation uses a 326 element look-up table
+    %% for int_pow(10, N) where we do not.
+    case Est >= 0 of
+        true ->
+            fixup(R, S * int_pow(10, Est), MPlus, MMinus, Est,
+                  LowOk, HighOk);
+        false ->
+            Scale = int_pow(10, -Est),
+            fixup(R * Scale, S, MPlus * Scale, MMinus * Scale, Est,
+                  LowOk, HighOk)
+    end.
+
+fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) ->
+    TooLow = case HighOk of
+                 true ->
+                     (R + MPlus) >= S;
+                 false ->
+                     (R + MPlus) > S
+             end,
+    case TooLow of
+        true ->
+            [(K + 1) | generate(R, S, MPlus, MMinus, LowOk, HighOk)];
+        false ->
+            [K | generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk)]
+    end.
+
+generate(R0, S, MPlus, MMinus, LowOk, HighOk) ->
+    D = R0 div S,
+    R = R0 rem S,
+    TC1 = case LowOk of
+              true ->
+                  R =< MMinus;
+              false ->
+                  R < MMinus
+          end,
+    TC2 = case HighOk of
+              true ->
+                  (R + MPlus) >= S;
+              false ->
+                  (R + MPlus) > S
+          end,
+    case TC1 of
+        false ->
+            case TC2 of
+                false ->
+                    [D | generate(R * 10, S, MPlus * 10, MMinus * 10,
+                                  LowOk, HighOk)];
+                true ->
+                    [D + 1]
+            end;
+        true ->
+            case TC2 of
+                false ->
+                    [D];
+                true ->
+                    case R * 2 < S of
+                        true ->
+                            [D];
+                        false ->
+                            [D + 1]
+                    end
+            end
+    end.
+
+unpack(Float) ->
+    <<Sign:1, Exp:11, Frac:52>> = <<Float:64/float>>,
+    {Sign, Exp, Frac}.
+
+frexp1({_Sign, 0, 0}) -> {0.0, 0};
+frexp1({Sign, 0, Frac}) ->
+    Exp = log2floor(Frac),
+    <<Frac1:64/float>> = <<Sign:1, ?FLOAT_BIAS:11, (Frac-1):52>>,
+    {Frac1, -(?FLOAT_BIAS) - 52 + Exp};
+frexp1({Sign, Exp, Frac}) ->
+    <<Frac1:64/float>> = <<Sign:1, ?FLOAT_BIAS:11, Frac:52>>,
+    {Frac1, Exp - ?FLOAT_BIAS}.
+
+log2floor(Int) -> log2floor(Int, 0).
+log2floor(0, N) -> N;
+log2floor(Int, N) -> log2floor(Int bsr 1, 1 + N).
+
+
+transform_digits(Place, [0 | Rest]) -> transform_digits(Place, Rest);
+transform_digits(Place, Digits) -> {Place, [$0 + D || D <- Digits]}.
+
+frexp_int(F) ->
+    case unpack(F) of
+        {_Sign, 0, Frac} ->
+            {Frac, ?MIN_EXP};
+        {_Sign, Exp, Frac} ->
+            {Frac + (1 bsl 52), Exp - 53 - ?FLOAT_BIAS}
+    end.
+
+

+ 7 - 0
src/nitro_pickle.erl

@@ -0,0 +1,7 @@
+-module(nitro_pickle).
+-compile(export_all).
+
+pickle(Data) -> base64:encode(term_to_binary({Data, now()}, [compressed])).
+depickle(PickledData) ->
+    try {Data, _PickleTime} = binary_to_term(base64:decode(wf:to_binary(PickledData))), Data
+    catch _:_ -> undefined end.

+ 18 - 0
src/render/wf_event.erl

@@ -0,0 +1,18 @@
+-module(wf_event).
+-author('Maxim Sokhatsky').
+-include_lib ("n2o/include/wf.hrl").
+-compile(export_all).
+
+new(bin,Data) -> <<"ws.send(enc(tuple(atom('bin'),bin('",(wf:pickle(Data))/binary,"'))));">>.
+
+new(undefined, _, _, _, _, _) -> <<>>;
+new(Postback, Element, Delegate, Name, Data, Source) ->
+    Module = nitro:coalesce([Delegate, ?CTX#cx.module]),
+    Join=fun([]) -> []; ([E]) -> [$'|E]++[$'];
+        ([H|T]) -> [[$'|H]++[$']] ++ [ [$,,$'|E]++[$'] || E <- T ] end,
+    Event = #ev{name=Name, module=Module, msg=Postback, trigger=Element},
+    erlang:list_to_binary([ <<"{ if (validateSources([">>,
+        Join([ case is_atom(S) of true -> atom_to_list(S); false -> S end || S <- Source, S =/= []]),
+        <<"])) ws.send(enc(tuple(atom('">>,nitro:to_binary(application:get_env(n2o,event,pickle)),
+        <<"'),bin('">>,Element,<<"'),bin('">>,nitro:pickle(Event),<<"'),">>,Data,
+        <<")));else console.log('Validation Error'); }">> ]).

+ 11 - 0
src/render/wf_render.erl

@@ -0,0 +1,11 @@
+-module(wf_render).
+-include_lib("n2o/include/wf.hrl").
+-compile(export_all).
+
+render_item(E) when element(2,E) == element -> wf_render_elements:render_element(E);
+render_item(E) when element(2,E) == action  -> wf_render_actions:render_action(E);
+render_item(E) -> E.
+render(<<E/binary>>) -> E;
+render(undefined) -> [];
+render(Elements) when is_list(Elements) -> [ render_item(E) || E <- lists:flatten(Elements) ];
+render(Elements) -> render_item(Elements).

+ 13 - 0
src/render/wf_render_actions.erl

@@ -0,0 +1,13 @@
+-module(wf_render_actions).
+-author('Andrew Zadorozhny').
+-include_lib ("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_action(Action) ->
+    Module = element(#action.module,Action),
+    Res = Module:render_action(Action),
+    case Res of
+         Res when is_tuple(Res) -> render_action(Res);
+         Str when is_list(Str) -> Str;
+         _ -> [] end.
+

+ 47 - 0
src/render/wf_render_elements.erl

@@ -0,0 +1,47 @@
+-module (wf_render_elements).
+-author('Maxim Sokhatsky').
+-include_lib ("nitro/include/nitro.hrl").
+-compile(export_all).
+
+render_element(E) when is_list(E) -> E;
+render_element(Element) when is_tuple(Element) ->
+    Id = case element(#element.id,Element) of
+        undefined -> undefined; % wf:temp_id();
+        L when is_list(L) -> L;
+        Other -> nitro:to_list(Other) end,
+    case element(#element.actions,Element) of undefined -> skip; Actions -> nitro:wire(Actions) end,
+    Tag = case element(#element.html_tag,Element) of undefined -> nitro:to_binary(element(1, Element)); T -> T end,
+    case element(#element.validation,Element) of
+         [] -> skip;
+         Code ->
+         nitro:wire(nitro:f("{var name='~s'; qi(name)"
+           ".addEventListener('validation',"
+              "function(e) { if (!(~s)) e.preventDefault(); });"
+              "qi(name).validation = true;}",[Id,Code]))
+            end,
+    case element(#element.module,Element) of
+        undefined -> 
+	    default_render(Tag, Element);
+        Module -> 
+	    wf:to_binary(Module:render_element(setelement(#element.id,Element,Id))) end;
+render_element(Element) -> wf:error("Unknown Element: ~p",[Element]).
+
+default_render(Tag, Record) ->
+    wf_tags:emit_tag(Tag, wf:render(element(#element.body,Record)),
+        lists:append([
+           [{<<"id">>,              element(#element.id, Record)},
+            {<<"class">>,           element(#element.class, Record)},
+            {<<"style">>,           element(#element.style, Record)},
+            {<<"title">>,           element(#element.title, Record)},
+            {<<"accesskey">>,       element(#element.accesskey, Record)},
+            {<<"contenteditable">>, element(#element.contenteditable, Record)},
+            {<<"contextmenu">>,     element(#element.contextmenu, Record)},
+            {<<"dir">>,             element(#element.dir, Record)},
+            {<<"draggable">>,       element(#element.draggable, Record)},
+            {<<"dropzone">>,        element(#element.dropzone, Record)},
+            {<<"hidden">>,          element(#element.hidden, Record)},
+            {<<"lang">>,            element(#element.lang, Record)},
+            {<<"spellcheck">>,      element(#element.spellcheck, Record)},
+            {<<"translate">>,       element(#element.translate, Record)}],
+        element(#element.data_fields, Record),
+        element(#element.aria_states, Record)])).

+ 28 - 0
src/render/wf_tags.erl

@@ -0,0 +1,28 @@
+-module(wf_tags).
+-author('Maxim Sokhatsky').
+-include_lib("n2o/include/wf.hrl").
+-compile(export_all).
+-define(VOID(Tag),  (Tag == <<"br">>     orelse Tag == <<"hr">>
+              orelse Tag == <<"link">>   orelse Tag == <<"img">> 
+              orelse Tag == <<"input">>  orelse Tag == <<"link">>
+              orelse Tag == <<"meta">>   orelse Tag == <<"param">>
+              orelse Tag == <<"base">>   orelse Tag == <<"area">>
+              orelse Tag == <<"col">>    orelse Tag == <<"command">> orelse Tag == <<"option">>
+              orelse Tag == <<"keygen">> orelse Tag == <<"source">>)).
+
+emit_tag(TagName, Props) -> [<<"<">>,TagName] ++ write_props(Props) ++ [<<"/>">>].
+emit_tag(TagName, undefined, Props) -> emit_tag(TagName, [], Props);
+emit_tag(TagName, [undefined], Props) -> emit_tag(TagName, [], Props);
+emit_tag(TagName, [], Props) when ?VOID(TagName) -> emit_tag(TagName, Props);
+emit_tag(TagName, [], Props) -> [<<"<">>,TagName,write_props(Props),<<">">>,<<"</">>,TagName,<<">">>];
+emit_tag(TagName, Content, Props) -> [<<"<">>,TagName,write_props(Props),<<">">>, Content,<<"</">>,TagName,<<">">>].
+write_props(Props) -> lists:map(fun display_property/1, Props).
+display_property({_, undefined}) -> [];
+display_property({_, []}) -> [];
+display_property({<<"class">>=Id, Value}) -> prop({Id,Value});
+display_property({<<"data-toggle">>=Id, Value}) -> prop({Id,Value});
+display_property({Prop, Value}) -> [<<" ">>, wf:to_binary(Prop), <<"=\"">>, wf:to_binary(Value), <<"\"">>].
+
+prop({Id, Value}) when is_atom(Value) -> [<<" ">>,Id,<<"=\"">>, wf:to_binary(Value), <<"\"">>];
+prop({Id, Value}) when is_binary(Value) -> [<<" ">>,Id,<<"=\"">>, Value, <<"\"">>];
+prop({Id, Value}) -> [<<" ">>,Id,<<"=\"">>, string:join([wf:to_list(V) || V <-Value ]," "), <<"\"">>].