elements.tex 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. \section{Elements}
  2. \paragraph{}
  3. With N2O you don't need to use HTML at all. Instead you define your page
  4. in the form of Erlang records so that the page is type checked at the compile time.
  5. This is a classic CGI approach for compiled pages and it gives us all the benefits of
  6. compile time error checking and provides DSL for client and server-side rendering.
  7. \paragraph{}
  8. Nitrogen elements, by their nature, are UI control primitives
  9. that can be used to construct Nitrogen pages with Erlang internal DSL.
  10. They are compiled into HTML and JavaScript.
  11. Behavior of all elements is controlled on server-side and all the communication
  12. between browser and server-side is performed over WebSocket channels.
  13. Hence there is no need to use POST requests or HTML forms.
  14. \subsection{Static Elements: HTML}
  15. The core set of HTML elements includes br, headings, links, tables, lists and image tags.
  16. Static elements are transformed into HTML during rendering.
  17. \paragraph{}
  18. Static elements could also be used as placeholders for other HTML elements.
  19. Usually ``static'' means elements that don't use postback parameter:
  20. \vspace{1\baselineskip}
  21. \begin{lstlisting}
  22. #textbox { id=userName, body= <<"Anonymous">> },
  23. #panel { id=chatHistory, class=chat_history }
  24. \end{lstlisting}
  25. \vspace{1\baselineskip}
  26. This will produce the following HTML code:
  27. \vspace{1\baselineskip}
  28. \begin{lstlisting}
  29. <input value="Anonymous" id="userName" type="text"/>
  30. <div id="chatHistory" class="chat_history"></div>
  31. \end{lstlisting}
  32. \newpage
  33. \subsection{Active Elements: HTML and JavaScript}
  34. There are form elements that provide information for the server
  35. and gather user input: button, radio and check buttons, text box area and password box.
  36. Form elements usually allow to assign an Erlang postback handler to specify action behavior.
  37. These elements are compiled into HTML and JavaScript. For example, during rendering, some
  38. Actions are converted to JavaScript and sent to be executed in the browser.
  39. Element definition specifies the list of {\bf source} elements that provide data for event's callback.
  40. \vspace{1\baselineskip}
  41. \begin{lstlisting}
  42. {ok,Pid} = wf:async(fun() -> chat_loop() end),
  43. #button { id=sendButton, body= <<"Send">>,
  44. postback={chat,Pid}, source=[userName,message] }.
  45. \end{lstlisting}
  46. \vspace{1\baselineskip}
  47. This will produce the following HTML:
  48. \begin{lstlisting}
  49. <input value="Chat" id="sendButton" type="button"/>
  50. \end{lstlisting}
  51. and JavaScript code:
  52. \begin{lstlisting}
  53. $('#sendButton').bind('click',function anonymous(event) {
  54. ws.send(Bert.encodebuf({
  55. source: Bert.binary('sendButton'),
  56. pickle: Bert.binary('g1AAAINQAAAAdX...'),
  57. linked: [
  58. Bert.tuple(Bert.atom('userName'),
  59. utf8.toByteArray($('#userName').val())),
  60. Bert.tuple(Bert.atom('message'),
  61. utf8.toByteArray($('#message').val()))] })); });
  62. \end{lstlisting}
  63. \vspace{1\baselineskip}
  64. If postback action is specified then the page module must include a callback to handle postback info:
  65. \vspace{1\baselineskip}
  66. \begin{lstlisting}
  67. event({chat,Pid}) ->
  68. wf:info(?MODULE, "User ~p Msg ~p",
  69. [wf:q(userName),wf:q(message)]).
  70. \end{lstlisting}
  71. \vspace{1\baselineskip}
  72. \newpage
  73. \subsection{Base Element}
  74. Each HTML element in N2O DSL has record compatibility with the base element.
  75. \vspace{1\baselineskip}
  76. \begin{lstlisting}
  77. #element { ancestor=element,
  78. module,
  79. id,
  80. actions,
  81. class=[],
  82. style=[],
  83. source=[],
  84. data_fields=[],
  85. aria_states=[],
  86. body,
  87. role,
  88. tabindex,
  89. show_if=true,
  90. html_tag=Tag,
  91. title }.
  92. \end{lstlisting}
  93. \vspace{1\baselineskip}
  94. Here {\bf module} is an Erlang module that contains a render function.
  95. Data and Aria HTML custom fields are common attributes for all elements.
  96. In case element name doesn't correspond to HTML tag, {\bf html\_tag} field provided.
  97. {\bf body} field is used as element contents for all elements.
  98. \paragraph{}
  99. Most HTML elements are defined as basic elements. You can even choose element's
  100. name different from its original HTML tag name:
  101. \vspace{1\baselineskip}
  102. \begin{lstlisting}
  103. -record(h6, ?DEFAULT_BASE).
  104. -record(tbody, ?DEFAULT_BASE).
  105. -record(panel, ?DEFAULT_BASE_TAG(<<"div">>)).
  106. -record('div', ?DEFAULT_BASE_TAG(<<"div">>)).
  107. \end{lstlisting}
  108. \vspace{1\baselineskip}
  109. \newpage
  110. \subsection{DTL Template {\bf \#dtl}}
  111. DTL stands for Django Template Language. A DTL element lets to construct HTML
  112. snippet from template with given placeholders for further substitution.
  113. Fields contain substitution bindings proplist, filename and templates folder.
  114. \vspace{1\baselineskip}
  115. \begin{lstlisting}
  116. -record(dtl, {?ELEMENT_BASE(element_dtl),
  117. file="index",
  118. bindings=[],
  119. app=web,
  120. folder="priv/templates",
  121. ext="html",
  122. bind_script=true }).
  123. \end{lstlisting}
  124. \vspace{1\baselineskip}
  125. Consider we have {\bf prod.dtl} file in {\bf priv/templates} folder with two
  126. placeholders \{\{title\}\}, \{\{body\}\} and default placeholder for JavaScript \{\{script\}\}.
  127. All placeholders except \{\{script\}\} should be specified in \#dtl element.
  128. Here is an example of how to use it:
  129. \vspace{1\baselineskip}
  130. \begin{lstlisting}
  131. body() -> "HTML Body".
  132. main() ->
  133. [ #dtl { file="prod", ext="dtl",
  134. bindings=[{title,<<"Title">>},{body,body()}]} ].
  135. \end{lstlisting}
  136. \vspace{1\baselineskip}
  137. You can use templates not only for pages, but for controls as well. Let's say we want
  138. to use DTL iterators for constructing list elements:
  139. \vspace{1\baselineskip}
  140. \begin{lstlisting}[caption=table.html]
  141. {% for i in items %} <a href="{{i.url}}">{{i.name}}</a><br>
  142. {% empty %} <span>No items available :-(</span>
  143. {% endfor %}
  144. \end{lstlisting}
  145. \vspace{1\baselineskip}
  146. Here is an example of how to pass variables to the DTL template we've just defined:
  147. \vspace{1\baselineskip}
  148. \begin{lstlisting}
  149. #dtl{file="table", bind_script=false, bindings=[{items,
  150. [ {[{name, "Apple"}, {url, "http://apple.com"}]},
  151. {[{name, "Google"}, {url, "http://google.com"}]},
  152. {[{name, "Microsoft"}, {url, "http://microsoft.com"}]} ]}]}.
  153. \end{lstlisting}
  154. \vspace{1\baselineskip}
  155. bind\_script should be set to true for page templates. When control elements are rendered from DTL,
  156. bind\_script should be set to false.
  157. \subsection{Button {\bf \#button}}
  158. \paragraph{}
  159. \begin{lstlisting}
  160. -record(button, {?ELEMENT_BASE(element_button),
  161. type= <<"button">>,
  162. name,
  163. value,
  164. postback,
  165. delegate,
  166. disabled}).
  167. \end{lstlisting}
  168. \paragraph{}
  169. Sample:
  170. \begin{lstlisting}
  171. #button { id=sendButton, body= <<"Send">>,
  172. postback={chat,Pid}, source=[userName,message] }.
  173. \end{lstlisting}
  174. \subsection{Link {\bf \#dropdown}}
  175. \begin{lstlisting}
  176. -record(dropdown, {?ELEMENT_BASE(element_dropdown),
  177. options,
  178. postback,
  179. delegate,
  180. value,
  181. multiple=false,
  182. disabled=false,
  183. name}).
  184. -record(option, {?ELEMENT_BASE(element_select),
  185. label,
  186. value,
  187. selected=false,
  188. disabled}).
  189. \end{lstlisting}
  190. \paragraph{}
  191. Sample:
  192. \begin{lstlisting}
  193. #dropdown { id=drop,
  194. value="2",
  195. postback=combo,
  196. source=[drop], options=[
  197. #option { label= <<"Microsoft">>, value= <<"Windows">> },
  198. #option { label= <<"Google">>, value= <<"Android">> },
  199. #option { label= <<"Apple">>, value= <<"Mac">> }
  200. ]},
  201. \end{lstlisting}
  202. \newpage
  203. \subsection{Link {\bf \#link}}
  204. \paragraph{}
  205. \begin{lstlisting}
  206. -record(link, {?ELEMENT_BASE(element_link),
  207. target,
  208. url="javascript:void(0);",
  209. postback,
  210. delegate,
  211. name}).
  212. \end{lstlisting}
  213. \vspace{1\baselineskip}
  214. \subsection{Text Editor {\bf \#textarea}}
  215. \paragraph{}
  216. \vspace{1\baselineskip}
  217. \begin{lstlisting}
  218. -record(textarea, {?ELEMENT_BASE(element_textarea),
  219. placeholder,
  220. name,
  221. cols,
  222. rows,
  223. value}).
  224. \end{lstlisting}
  225. \vspace{1\baselineskip}