Customizing site appearance¶
Understading layers and skins¶
Creating a new skin¶
A Skin is a tagging interface for associating media, javascript and CSS resources to a renderer
1) Create a new Layer to your skin¶
Build a new interface inherit from ICustomLayer
class ICustomLayer(ICustomLayer):
"""skin layer"""
Define an utility providing ISkin with the custom label and the layer interface
@utility_config(name='Custom skin', provides=ISkin)
class CustomSkin(object):
"""custom root skin"""
label = _("Custom: skin")
layer = ICustomLayer
2) Declare the layer adapter¶
@adapter_config(context=(Interface, ICustomLayer, Interface), provides=IResources)
class CustomSkinResourcesAdapter(ContextRequestViewAdapter):
"""Custom skin resources adapter"""
def get_resources(self):
mycms.need()
We have defined a Multiadapter with context=(context, request, view).
Note
In the ZMI website you can now change the default graphical theme by you custom skin
Adding resources library¶
from fanstatic import Library, Resource
from pyams_default_theme import pyams_default_theme
#Library(name, folder_path)
library = Library('mycms', 'resources')
#Resource(library, path_to_static)
mycms_css = Resource(library, 'css/mystyle.css',)
mycms_js = Resource(library, 'js/pyams-default.js',
depends=(pyams_default_theme, )
bottom=True
)
Resource
can include others resources already defined with depends attribute, here pyams_default_theme.
Overriding templates¶
The simplest is to create a new class that inherits from the existing Renderer and modify this template. After that all you have to define a new adapter name and a new label.
1 2 3 4 5 6 7 8 9 | # New custom contact paragraph renderer
@adapter_config(name='custom', context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer)
@template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer)
class ContactParagraphCustomRenderer(ContactParagraphDefaultRenderer):
"""Context paragraph custom renderer"""
label = _("Custom contact renderer")
#settings_interface = IContactParagraphDefaultRendererSettings
|
In this example, we have defined an adapter named ‘custom’ with IContactParagraph
,
IPyAMSLayer
as context and provides ISharedContentRenderer
interface.
Using @template_config()
decorator, the renderer will be displayed in html container according to the template
templates/contact-custom.pt
The new renderer inherit of ContactParagraphDefaultRenderer
, have a new label (line 8)
and this associated settings_interface is not modify(line 9)
Tip
You can override the template of a renderer easily with the function pyams_template.template.override_template()
It’s takes the context and the new template path as params.
Creating custom renderer¶
We can define a new settings for the renderer, to do that we start by creating an interface:
a) Create setting interface for the renderer¶
class IPhotoRendererSettings(Interface):
"""Custom renderer settings interface"""
display_photo = Bool(title=_("Show photo?"),
description=_("Display contact photo"),
required=True,
default=True)
can_display_photo = Attribute("Check if photo can be displayed")
We have created an interface with two attributes display_photo and can_display_photo Then we create an implemantation of the interface
@implementer(IPhotoRendererSettings)
class PhotoRendererSettings(Persistent, Location):
"""Custom renderer settings"""
display_photo = FieldProperty(IPhotoRendererSettings['display_photo'])
@property
def can_display_photo(self):
contact = IContactParagraph(self.__parent__)
if not contact.photo:
return False
return self.display_photo
b) Create an adapter for the render setting interface¶
- With
@adapter_config()
we declare a new adapter that applies to a context and provide the interface of - renderer settings
PHOTO_RENDERER_SETTINGS_KEY = 'pyams_content.contact.renderer:photo'
@adapter_config(context=IContactParagraph, provides=IPhotoRendererSettings)
def custom_renderer_settings_factory(context):
"""Contact paragraph default renderer settings factory"""
return get_annotation_adapter(context, PHOTO_RENDERER_SETTINGS_KEY,
CustomRendererSettings)
In this example the settings interface adapter is defined with IContactParagraph as context and provide IPhotoRendererSettings.
c) Create an adapter for the render interface¶
@adapter_config(context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer)
@template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer)
class PhotoRenderer(BaseContentRenderer):
"""Context paragraph custom renderer"""
label = _("Custom contact renderer")
settings_interface = IPhotoRendererSettings
Add settings interface to the renderer settings_interface = IPhotoRendererSettings
Tip
When a setting_interface is associated to a renderer, you can access to settings attributes through the template
How to define or change a template for a specific skin?¶
Override the default template for a renderer¶
If you want to modify the template for a particular rendering mode, you can use the function override_template()
from pyams_template.template import override_template
from my_website.skin.public.layer import ICustomLayer
from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
override_template(context=KeyNumberPortletHorizontalRenderer,
template="templates/keynumber-horizontal.pt",
layer=ICustomLayer
)
This new template can be applied to a particular Skin by specifying on which layer to use this renderer (ex: layer=IMyWebsiteLayer)
Redefine the default template for a renderer¶
You must redefine an adapter to add new variables or static resources for your new template,
# import interfaces
from my_website.skin.public.layer import ICustomLayer
from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings
from pyams_portal.interfaces import IPortletRenderer, IPortalContext
# import packages
from my_website.skin.public import my_carousel_init ,my_carousel_animation
from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
from pyams_template.template import template_config
from pyams_utils.adapter import adapter_config
from zope.interface import Interface
@adapter_config(context=(IPortalContext, IBaseLayer, Interface, IKeyNumberPortletSettings),
provides=IPortletRenderer)
@template_config(template='templates/keynumber-horizontal.pt', layer=ICustomLayer)
class MyCustomKeyNumberPortletHorizontalRenderer(KeyNumberPortletHorizontalRenderer):
"""Key numbers portlet horizontal renderer"""
resources = (my_carousel_init, my_carousel_animation)
The attribute resources
is used to load in the template static resources. The application will automatically
integrate resource content when the template is calling.