Parts & Pages
-------------
.. _override-part-of-page:
How do I override part of a part/page?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Page.parts
.. uses Fragment.children
.. Attrs
This is all just *standard* iommi declarative magic, but as you are likely new to it
this might take a while to get used to. Let's say you created yourself a master template
for your site.
.. code-block:: python
class BasePage(Page):
title = html.h1('My awesome webpage')
subtitle = html.h2('It rocks')
.. raw:: html
▼ Hide result
Toggle structure
Which you can use like this:
.. code-block:: python
class IndexPage(BasePage):
body = 'body'
index = IndexPage(parts__subtitle__children__child='Still rocking...').as_view()
.. raw:: html
▼ Hide result
Toggle structure
or as a function based view:
.. code-block:: python
def index(request):
return IndexPage(parts__subtitle__children__child='Still rocking...')
.. raw:: html
► Show result
Toggle structure
Here you can see that `Part` s (`Page` s are themselves `Part` s) form a tree and the direct children are gathered in the `parts` namespace. Here we overwrote a leaf of
an existing namespace, but you can also add new elements or replace bigger
parts (and most of the time it doesn't matter if you use the `class Meta` or the
keyword arguments to init syntax):
.. code-block:: python
class IndexPage(BasePage):
title = html.img(
attrs=dict(
src='https://docs.iommi.rocks/_static/logo_with_outline.svg',
alt='iommi logo',
width='70px',
),
)
index = IndexPage(parts__subtitle=None)
.. raw:: html
▼ Hide result
Toggle structure
In the above we replaced the title and removed the subtitle element completely. The
latter of which shows one of the gotchas as only `str`, `Part` and the django
template types are gathered into the parts structure when a `Part` class definition
is processed. As `None` is not an instance of those types, you can remove things
by setting their value to `None`.
.. _title-of-page:
How do I set the title of my page?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Page.title
The title of a the page is text shown in the browser tab.
.. code-block:: python
Page(title='The title in the browser')
Note that this is different from:
.. code-block:: python
class MyPage(Page):
title = Header('A header element in the dom')
MyPage()
Which is equivalent to:
.. code-block:: python
Page(parts__title=Header('A header element in the dom'))
.. _context-of-page:
How do I specify the context used when a Template is rendered?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Page.context
.. code-block:: python
class MyPage(Page):
body = Template("""A django template was rendered on {{today}}.""")
def index(request):
context = {'today': date.today()}
return MyPage(context=context)
.. raw:: html
▼ Hide result
Toggle structure
You can also insert items in the context via the declaration. This
not only makes the above shorter, but also makes it easy to write abstractions that
can be extended later:
.. code-block:: python
my_page = Page(
parts__body=Template("""A django template was rendered on {{today}}."""),
context__today=lambda **_: date.today(),
).as_view()
.. raw:: html
▼ Hide result
Toggle structure
.. _cookbook-menu:
How do I make a menu?
~~~~~~~~~~~~~~~~~~~~~
.. uses Menu.sub_menu
.. uses Menu.items_container
.. uses Menu.sort
.. uses MenuItem.url
.. uses MenuItem.sub_menu
.. uses MenuItem.regex
.. uses MenuItem.group
.. uses MenuItem.sort
.. uses MenuItem.a
.. uses MenuItem.active_class
.. uses MenuItem.active_class_on_item
A `Menu` is built from `MenuItem` s in its `sub_menu`. Each item's `url` defaults
to ``//``, and the item whose `regex` matches the current URL gets the
`active_class` (put that class on the item itself instead of its link with
`active_class_on_item`). Nest items by giving a `MenuItem` its own `sub_menu`. By
default items keep their declared order; set `sort=True` to sort them by name. The
```` tag of an item is configured via `a`, and the element wrapping the whole
list of items via `items_container`:
.. code-block:: python
menu = Menu(
sub_menu=dict(
root=MenuItem(url='/', display_name='Home'),
albums=MenuItem(),
artists=MenuItem(
active_class_on_item=True,
sub_menu=dict(
black_sabbath=MenuItem(),
ozzy=MenuItem(),
),
),
),
)
.. raw:: html
▼ Hide result
Toggle structure
.. _custom-endpoint:
How do I add a custom endpoint?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Endpoint.func
.. uses Endpoint.http_methods
Any `Part` can have custom endpoints under `endpoints`. Give an endpoint a `func`
that returns the response - an `HttpResponse`, a `Part` (which is rendered for
you), or anything JSON-serializable. It answers ``?/``. Allow POST by setting
`http_methods`:
.. code-block:: python
page = Page(
parts__h1=html.h1('Hi!'),
endpoints__echo__func=lambda value, **_: value,
)
.. _custom-assets:
How do I add CSS or JavaScript assets to a page?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Asset.children
.. uses Asset.in_body
Add `Asset` s under `assets` (on any `Part`, or in your `Style`). An `Asset` is a
`Fragment`, so you set its tag and `children` like any other fragment. By default
assets render in the ````; set `in_body=True` to render them at the end of
the ```` instead, which is handy for scripts:
.. code-block:: python
page = Page(
assets__custom_css=Asset.css(attrs__href='/static/custom.css'),
assets__custom_script=Asset(
tag='script',
children__text='console.log("hi");',
in_body=True,
),
)
.. raw:: html
▼ Hide result
Toggle structure
.. _fragment-children:
How do I set the content of a fragment-like part?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Action.children
.. uses Header.children
.. uses Container.children
Many parts are `Fragment` s - an HTML tag plus a dict of `children`. `Action`,
`Header` and a table's `container` all work this way, so you build up their
contents through `children`:
.. code-block:: python
page = Page(
parts__heading=Header(
children__text='Albums',
children__count=html.span(' (2)'),
),
parts__link=Action(
children__text='Add album',
children__icon=html.i(attrs__class={'fa': True, 'fa-plus': True}),
attrs__href='/albums/create/',
),
)
.. raw:: html
▼ Hide result
Toggle structure
.. _action-group:
How do I group actions together?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. uses Action.group
Give actions the same `group` and they are rendered together (for example in a
dropdown):
.. code-block:: python
form = Form(
fields__name=Field(),
actions__save=Action.submit(group='Manage'),
actions__reset=Action.button(display_name='Reset', group='Manage'),
)
.. raw:: html
▼ Hide result
Toggle structure