Rich content models =================== GLAMkit's approach to rich content is based on the ``fluent-contents`` system. In that system, content models contain placeholders, and placeholders contain content items. .. TODO: describe the system. .. TODO: link to creating a rich content model. .. TODO: check usage of content items vs content plugins throughout. Placeholders ------------ When an end-user editor edits rich content in GLAMkit, she adds **Content Plugins** into one or more **Placeholders**. Placeholders are specified in the html template that is associated with the rich content model. At render time, each ``render_placeholder`` template tag renders all of the content items as they were added by the editor. Allowing direct access to slot contents with ``PlaceholderDescriptor`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are several times where it is useful to gain direct access to a slots contents without wanting to render them. The is especially useful in templates to detect if there are any slot contents so that the rendered slot output can be wrapped in appropriate tags. Adding ``PlaceholderDescriptor`` to a model class ````````````````````````````````````````````````` ``PlaceholderDescriptor`` assumes that ``Placeholder`` objects are created for the appropriate model class. To add the descriptor directly to the model class create a property on the class and create an instance of ``PlaceholderDescriptor``. :: from icekit.plugins.descriptors import PlaceholderDescriptor class TestFluentPage(AbstractFluentPage): slots = PlaceholderDescriptor() For external libraries a monkey patching utility is provided. Calling the monkey patch function with the model class is all that is required. :: from fluent_pages.pagetypes.fluentpage.models import FluentPage from icekit.plugins.descriptors import contribute_to_class contribute_to_class(FluentPage) Using ``PlaceholderDescriptor`` ``````````````````````````````` When accessed via an instance of a model class with ``PlaceholderDescriptor`` enabled a ``PlaceholderAccess`` object is created with all of the slot names available as attributes. If we have an instance with contents in a ``Placeholder`` named ``main`` we would access the contents by accessing the property such as ``instance.slots.main``. This will return an ordered ``QuerySet`` of content items for that slot. If not corresponding slot exists on the referenced property an ``AttributeError`` will be thrown. This is swallowed in templates. Fluent contents will only create a ``Placeholder`` object when data is to be added to the relevant slot so the ``AttributeError`` may be thrown before the initial data is created. You may also perform the lookup in a dictionary style manner such as ``instance.slots['main']`` and if the slot referenced does not exist a ``KeyError`` will be raised. Template tags ````````````` As slot names are arbitrary strings they may use characters which wont allow access to attributes on descriptors in templates e.g. the '-' character. To help with this problem some template tags have been created. To use any of the following tags you will need to load ``icekit_tags`` into your template. To do this at the top of your template do the following: :: {% load icekit_tags %} The tag ``get_slot_contents`` may be used as a filter, or an assignment tag. In each of the below examples we will assume that we have an object named ``page`` with a ``PlaceholderDescriptor`` on it named ``slots`` and a placeholder with a slot named ``test-main``. To use this tag as a filter: :: {{ page.slots|get_slot_contents:'test-main' }} This will output the list of contents directly into your template (which is only useful for debugging). Each of the these items can be iterated and worked on as required e.g. :: {% for item in page.slots|get_slot_contents:'test-main' %} {{ item }} {% endfor %} The assignment tag will allow assignment to a variable name for use later in your template. If we wanted to assign the returned list into a variable named ``testname`` we can do the following: :: {% get_slot_contents page.slots 'test-main' as testname %} This will then let us work on the contents later in the template e.g. :: {% for item in testname %} {{ item }} {% endfor %} If a placeholder does not exist ``None`` will be returned.