/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
- = Templates and Scomps =
- The templates in Zotonic are based on django templates, using the excellent erlydtl library.
- See http://code.google.com/p/erlydtl/ for the implemented tags and release notes.
- == Template Locations ==
- The templates are searched for in two different locations:
- /zotonic/default/templates/
- /zotonic/priv/templates/
- 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.
- == Scomps ==
- Scomp is shorthand for screen component. A scomp is a module implementing logic and templates.
- Scomps can be included in the template using, for example:
- {% @button text="Hello" action={growl text="Hello World" stay="1"} %}
- {% @button text=somevar action={growl text="Hello World" stay="1"} %}
- This button scomp has two parameters, text and action. The action parameter is a tuple with two additional parameters.
- == Implementing Scomps ==
- Scomps come in two different variations, caching and non-caching.
- You can implement scomps by using the behaviours scomp and caching_scomp.
- A scomp has the following four functions:
- init(Args) -> {ok, State} | {error, Error}
- render(Params, Context, State) -> {ok, NewContext} | {error, Error}
- code_change(OldVsn, State, Extra) -> {ok}
- terminate(Reason, State) -> ok
-
- State = term()
- Params = proplist()
- Context = context()
- depends(Params, Context) -> {NewParams, MaxAge, Depend} | false
- Params = proplist()
- MaxAge = integer()
- Depend = TermList()
- == Templates, Scomps and Request Context State ==
- During the evaluation of scomps we are able to:
- - wire action
- - add script
- - add validator
- - add variable (accessible only by other scomps)
- 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
- is a context, unless there are no collected scripts.
- Process state diagram, how all processes work together to render a scomp:
- Resource Template ScompServer Scomp Page/Session/User
- |
- |------------> render(Template,ReqContext)
- |
- | ------------------------------- lookup missing var ---------->|
- |
- |<------------------------------------- value ------------------|
- |
- |------------------> render(Scomp,ReqContext)
- |
- |---------> render(ReqContext)
- : |
- (if cached) |
- : |
- |<--ReqContext--|
- |
- |
- |
- |
- |
- |<------------ Output ----------|
- |
- Filter scripts
- |
- |<---- Output ------|
- |
- reply user agent
- 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.
- == Things to do ==
- 1. Change the variable lookup in erlydtl_runtime.erl - Done.
- 2. Add extra parsing rules to erlydtl_parser.yrl - Done.
- 3. Build the new LALR parser - Done.
- 4. Add handling of scomp AST (abstract syntax tree) to erlydtl_compiler.erl - Done.
- 5. Create the scomp server (no caching for the moment) - Done.
- 6. Add script filter to z_template - Done.
- 7. Make test scomps - Done.
- == Code generated for the scomp calls ==
- {% @button text="Hello" action={growl text="Hello World" stay=1} %}
- gives an AST of:
- [{scomp,
- {identifier,{5,5},"button"},
- [{{identifier,{5,12},"text"},
- {string_literal,{5,17},"\"Hello\""}},
- {{identifier,{5,25},"action"},
- {{identifier,{5,33},"growl"},
- [{{identifier,{5,39},"text"},
- {string_literal,{5,44},"\"Hello World\""}},
- {{identifier,{5,58},"stay"},
- {number_literal,{5,63},"1"}}]}}]},
- Which should be translated to:
- case z_scomp:render(button, [{text,"Hello"},
- {action, {growl, [{text,"HelloWorld"}, {stay,1}]} }
- ], Variables)
- of
- {ok, Rendered} -> Rendered;
- {error, Reason} -> io_lib:format("error: ~p", Reason)
- end