/doc/Templates-and-scomps.txt

http://github.com/zotonic/zotonic · Plain Text · 134 lines · 95 code · 39 blank · 0 comment · 0 complexity · 64d96372caf5aa764610b98778b1afed MD5 · raw file

  1. = Templates and Scomps =
  2. The templates in Zotonic are based on django templates, using the excellent erlydtl library.
  3. See http://code.google.com/p/erlydtl/ for the implemented tags and release notes.
  4. == Template Locations ==
  5. The templates are searched for in two different locations:
  6. /zotonic/default/templates/
  7. /zotonic/priv/templates/
  8. Templates don't need to have an extension, they are just text files. Templates can also be found in subdirectories, as long as you give the subdirectory name with the template.
  9. == Scomps ==
  10. Scomp is shorthand for screen component. A scomp is a module implementing logic and templates.
  11. Scomps can be included in the template using, for example:
  12. {% @button text="Hello" action={growl text="Hello World" stay="1"} %}
  13. {% @button text=somevar action={growl text="Hello World" stay="1"} %}
  14. This button scomp has two parameters, text and action. The action parameter is a tuple with two additional parameters.
  15. == Implementing Scomps ==
  16. Scomps come in two different variations, caching and non-caching.
  17. You can implement scomps by using the behaviours scomp and caching_scomp.
  18. A scomp has the following four functions:
  19. init(Args) -> {ok, State} | {error, Error}
  20. render(Params, Context, State) -> {ok, NewContext} | {error, Error}
  21. code_change(OldVsn, State, Extra) -> {ok}
  22. terminate(Reason, State) -> ok
  23. State = term()
  24. Params = proplist()
  25. Context = context()
  26. depends(Params, Context) -> {NewParams, MaxAge, Depend} | false
  27. Params = proplist()
  28. MaxAge = integer()
  29. Depend = TermList()
  30. == Templates, Scomps and Request Context State ==
  31. During the evaluation of scomps we are able to:
  32. - wire action
  33. - add script
  34. - add validator
  35. - add variable (accessible only by other scomps)
  36. After rendering a template it is inspected to find all scripts, actions and validators. They are placed as #context records in the resulting iolist, the #contexts should be replaced by the 'render' record-attribute. There will be a special 'script' atom to signify the place where all collected scripts will be inserted. When the script atom is not found, then the result of the template
  37. is a context, unless there are no collected scripts.
  38. Process state diagram, how all processes work together to render a scomp:
  39. Resource Template ScompServer Scomp Page/Session/User
  40. |
  41. |------------> render(Template,ReqContext)
  42. |
  43. | ------------------------------- lookup missing var ---------->|
  44. |
  45. |<------------------------------------- value ------------------|
  46. |
  47. |------------------> render(Scomp,ReqContext)
  48. |
  49. |---------> render(ReqContext)
  50. : |
  51. (if cached) |
  52. : |
  53. |<--ReqContext--|
  54. |
  55. |
  56. |
  57. |
  58. |
  59. |<------------ Output ----------|
  60. |
  61. Filter scripts
  62. |
  63. |<---- Output ------|
  64. |
  65. reply user agent
  66. The scripts/actions/validators are similar to the ones defined with Nitrogen, though the record structure is redefined to accomodate easy construction by the Template compiler.
  67. == Things to do ==
  68. 1. Change the variable lookup in erlydtl_runtime.erl - Done.
  69. 2. Add extra parsing rules to erlydtl_parser.yrl - Done.
  70. 3. Build the new LALR parser - Done.
  71. 4. Add handling of scomp AST (abstract syntax tree) to erlydtl_compiler.erl - Done.
  72. 5. Create the scomp server (no caching for the moment) - Done.
  73. 6. Add script filter to z_template - Done.
  74. 7. Make test scomps - Done.
  75. == Code generated for the scomp calls ==
  76. {% @button text="Hello" action={growl text="Hello World" stay=1} %}
  77. gives an AST of:
  78. [{scomp,
  79. {identifier,{5,5},"button"},
  80. [{{identifier,{5,12},"text"},
  81. {string_literal,{5,17},"\"Hello\""}},
  82. {{identifier,{5,25},"action"},
  83. {{identifier,{5,33},"growl"},
  84. [{{identifier,{5,39},"text"},
  85. {string_literal,{5,44},"\"Hello World\""}},
  86. {{identifier,{5,58},"stay"},
  87. {number_literal,{5,63},"1"}}]}}]},
  88. Which should be translated to:
  89. case z_scomp:render(button, [{text,"Hello"},
  90. {action, {growl, [{text,"HelloWorld"}, {stay,1}]} }
  91. ], Variables)
  92. of
  93. {ok, Rendered} -> Rendered;
  94. {error, Reason} -> io_lib:format("error: ~p", Reason)
  95. end