You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/docs/themes/templates.rst

194 lines
6.1 KiB
ReStructuredText

Rendering Engine
=================
How it works
------------------------------------------------------
Every page has an associated API call, Template file, and Language File.
For example, if you navigate to `/topic/351/nodebb-wiki <http://community.nodebb.org/topic/351/nodebb-wiki>`_, the application will load three resources. The API return `/api/topic/351/nodebb-wiki <http://community.nodebb.org/api/topic/351/nodebb-wiki>`_ and the `template <http://community.nodebb.org/templates/topic.tpl>`_, in this example, "topic.tpl", and the appropriate `language file <community.nodebb.org/language/en_GB/topic.json>`_ "topic.json"*.
Just prepend api/ to the URL's path name to discover the JSON return. Any value in that return can be utilized in your template.
*A page's name corresponds to the template and language's filename (ex. ``http://domain.com/topic/xyz`` correlates to ``topic.tpl``). Sometimes this is not the case - ex. ``/user/xyz`` loads ``account.tpl``. Have a look at the ``custom_mapping`` section in ``public/templates/config.json`` for more details.
Templating Basics
------------------------------------------------------
Using the API return as your guide, you can utilize any of those values in your template/logic. Using the above API call as an example, for anything in the root level of the return you can do something like:
.. code:: html
{topic_name}
To access values in objects:
.. code:: html
{privileges.read}
And finally you can loop through arrays and create blocks like so:
.. code:: html
<!-- BEGIN posts -->
{posts.content}
<!-- END posts -->
The above will create X copies of the above block, for each item in the posts array.
Templating Logic
------------------------------------------------------
NodeBB's templating system implements some basic logic. Using the same API call as above for our example. You can write IF conditionals like so:
.. code:: html
<!-- IF unreplied -->
This thread is unreplied!
<!-- ENDIF unreplied -->
Another example:
.. code:: html
<!-- IF !disableSocialButtons -->
<button>Share on Facebook</button>
<!-- ELSE -->
Sharing has been disabled.
<!-- ENDIF !disableSocialButtons -->
We can check for the length of an array like so:
.. code:: html
<!-- IF posts.length -->
There be some posts
<!-- ENDIF posts.length -->
While looping through an array, we can check if our current index is the @first or @last like so:
.. code:: html
<!-- BEGIN posts -->
<!-- IF @first -->
<h1>Main Author: {posts.username}</h1>
<!-- ENDIF @first -->
{posts.content}
<!-- IF @last -->
End of posts. Click here to scroll to the top.
<!-- ENDIF @last -->
<!-- END posts -->
For more advanced documentation, have a look at the `templates.js <https://github.com/psychobunny/templates.js>`_ repository
Exposing template variables to client-side JavaScript
------------------------------------------------------
There are two ways of letting our JS know about data from the server-side, apart from WebSockets (TODO: will be covered in a different article).
Via jQuery.get
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If we require data from a different page we can make a ``$.get`` call to any other API call. For example, if we wanted to know more about a specific user we could make a call like so:
.. code:: javascript
$.get(RELATIVE_PATH + '/api/user/psychobunny', {}, function(user) {
console.log(user)
});
See this API call in action: http://community.nodebb.org/api/user/psychobunny
Via Template Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In topic.tpl for example, we can add a hidden input like so:
.. code:: html
<input type="hidden" template-variable="pageCount" value="{pageCount}" />
The template system will immediately parse all of these and expose them via the following method:
.. code:: html
ajaxify.variables.get('pageCount');
This is the ideal method of letting JS know about important variables within the template.
Internationalization
---------------------
The template engine interfaces with the internationalization system as well. We can embed variables into language strings. Let's use `this API call <http://community.nodebb.org/api/register>`_ as well as this `language file <http://community.nodebb.org/language/en_GB/register.json>`_ as an example. We can now do something like the following:
.. code:: html
[[register:help.username_restrictions, {minimumUsernameLength}, {maximumUsernameLength}]]
Which will translate this string:
.. code:: html
A unique username between %1 and %2 characters
to
.. code:: html
A unique username between 2 and 16 characters
Advanced Topics
---------------------
Dynamically requiring and rendering a template file from client-side JavaScript
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The template engine lazy loads templates on an as-needed basis and caches them. If your code requires a template or partial on-demand then you can :
.. code:: javascript
ajaxify.loadTemplate('myTemplate', function(myTemplate) {
var html = templates.parse(myTemplate, myData);
});
You can also access the invidual blocks inside each template, which is handy for doing things like (for example) rendering a new post's ``<li>`` and dynamically sticking it in an already loaded ``<ul>``
.. code:: html
Some stuff here...
<!-- BEGIN posts -->
We just want to pull this block only.
<!-- END posts -->
... some stuff here
.. code:: javascript
ajaxify.loadTemplate('myTemplate', function(myTemplate) {
var block = templates.getBlock(myTemplate, 'posts');
var html = templates.parse(block, myData);
});
Rendering templates on server-side Node.js
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The templating system hooks into Express just like most other templating frameworks. Just use either ``app.render`` or ``res.render`` to parse the appropriate template.
.. code:: javascript
res.render('myTemplate', myData);
.. code:: javascript
app.render('myTemplate', myData, function(err, parsedTemplate) {
console.log(parsedTemplate);
});