.. _topics-blocks:

======
Blocks
======

This section is about blocks in Merengue. Merengue blocks are components
which can be located in several places and render a fragment with information
(usually HTML). Blocks are defined inside plugins and registered when plugin
is activated.

The place of every block can be defined in admin site and you can even
using the Merengue `block reordering interface`_ to change blocks location.

.. _`block reordering interface`: http://www.merengueproject.org/features/visual-blocks-management/

Plugin tree with blocks
-----------------------

We know the conventional plugin tree (see :ref:`plugin development reference
<topics-plugins-development>`). Here we emphasize the files on which we are
going to work in this example:

.. code-block:: html

     /plugins/
         |-- news/
         |   |-- ...
         |   |-- config.py
         |   |-- blocks.py
         |   `-- templates/
         |       `-- news/
         |           |-- block_latest.html
         |
         ...


Example plugin block
--------------------

This is a ``blocks.py`` file code fragment:

.. code-block:: python

    from merengue.block.blocks import Block
    from plugins.news.views import get_news

    class LatestNewsBlock(Block):
        name = 'latestnews'
        default_place = 'leftsidebar'

        @classmethod
        def render(cls, request, place, context):
            news_list = get_news(5)
            return cls.render_block(request, template_name='news/block_latest.html',
                                    block_title='Latest news',
                                    context={'news_list': news_list})

* ``name`` is the block name.
* ``default_place`` indicates the place where the block will be showed by default.
* ``render`` is a similar function to the ``render_to_response`` Django function. This function is the responsible for displaying the block.
* ``news_list`` stores the number of news gotten by ``get_news``.
* ``template_name`` is the full name of the block template.
* ``block_title`` is the block title.
* ``context`` is a dictionary of values to render the template with.

About block rendering
---------------------

In a Merengue block, ``render`` method is a callback function which will be
called when Merengue is rendering blocks in location defined for that block.

The block rendering is done in some base templates. For example, in
`base/inc.leftsidebar.html`_ template, the blocks placed at ``leftsidebar`` are
rendered, using this ``render_blocks`` templatetags as follows:

.. code-block:: html+django

  {% load block_tags %}

  {% block leftsidebarblocks %}
    {% render_blocks "leftsidebar" %}
    {# more stuff #}
  {% endblock %}

This ``render_blocks`` templatetags will cause calling to ``render`` method
with ``leftsidebar`` passed in ``place`` parameter. Also, request and context
are passed by param, to be used in ``render`` method, if you want. Next
example is self-explanatory:

.. code-block:: python

    from merengue.block.blocks import Block

    class WhereIAmBlock(Block):
        name = 'whereiam'
        default_place = 'leftsidebar'

        @classmethod
        def render(cls, request, place, context):
            if place in ['leftsidebar', 'rightsidebar']:
                return 'I am in a side column'
            else:
                return 'I am in %s place' % place

.. _`base/inc.leftsidebar.html`: http://dev.merengueproject.org/browser/trunk/merengueproj/merengue/base/templates/base/inc.leftsidebar.html

Implementing the block template
-------------------------------

Let's back to ``LatestNewsBlock`` block. To finish block rendering we must
create a template inside ``block_latest.html``:

.. code-block:: html+django

    {% extends "block.html" %}

    {% block blockbody %}
    <ul>
    {% for n in news_list %}
        <li><a href="{{ n.get_absolute_url }}" title="{{ n }}">{{ n }}</a></li>
    {% endfor %}
    </ul>
    {% endblock %}

This template shows the title of the last published news. The number of news that is considered
*last news* is specified in render function inside the ``blocks.py`` (five in this case).

How to register the block
-------------------------

Our ``LatestNewsBlock`` class must be referenced in the plugin configuration inside ``config.py`` file:

.. code-block:: python

    from merengue.pluggable import Plugin
    from plugins.news.blocks import LatestNewsBlock
    #some stuff

    class PluginConfig(Plugin):
        #some stuff

        @classmethod
        def get_blocks(cls):
            return [LatestNewsBlock]

* ``get_blocks`` is a classmethod that returns the specified blocks that we want to register.

(( to be completed ))
