Actions and aliases
CMF 1.5, on which Plone 2.1 depends, brings two related concepts together: Actions and method aliases. Actions are a way of defining links, such as the portal tabs or the document actions that define the "print" and "send to" icons on standard documents. In particular, actions in the object and folder categories will appear as green "content tabs" in Plone. The standard ones are view, edit, properties and sharing.
In Plone 2.0, defining a custom view action was the standard way of defining the view template for a content type. However, as you have already seen in the section on dynamic views, this is better handled in Plone 2.1 using the default_view and suppl_views variables and letting CMFDynamicViewFTI do its magic.
The concept of method aliases means that even for other actions such as edit, properties or local_roles (the sharing tab), re-defining actions on a type is typically a bad idea. Method aliases are a way of standardising URLs via another level of indirection, so that if you navigate to /path/to/object/edit you will always get the correct template for editing the object.
ATContentTypes and BrowserDefaultMixin from CMFDynamicViewFTI define the standard actions and aliases. You should rarely need to add additional actions, and even more rarely change the standard ones. You can view (and change) actions and aliases from the Actions and Aliases tabs of an FTI in portal_types, as well as define them on your type using the actions and aliases variables.
As defined in ATContentTypes/content/base.py, the standard actions and aliases are:
actions = ({
'id' : 'view',
'name' : 'View',
'action' : 'string:${object_url}',
'permissions' : (View,)
},
{
'id' : 'edit',
'name' : 'Edit',
'action' : 'string:${object_url}/edit',
'permissions' : (ModifyPortalContent,),
},
{
'id' : 'metadata',
'name' : 'Properties',
'action' : 'string:${object_url}/properties',
'permissions' : (ModifyPortalContent,),
},
...
{
'id' : 'local_roles',
'name' : 'Sharing',
'action' : 'string:${object_url}/sharing',
'permissions' : (ManageProperties,),
},
)
aliases = {
'(Default)' : '(dynamic view)',
'view' : '(selected layout)',
'index.html' : '(dynamic view)',
'edit' : 'atct_edit',
'properties' : 'base_metadata',
'sharing' : 'folder_localrole_form',
'gethtml' : '',
'mkdir' : '',
}
Notice how actions resolve to URLs that are method aliases. Remember - actions are rendered as tabs. When you click a tab, the URL of that action is called. Hence, the edit action points to string:${object_url}/edit, which means that if you are at /path/to/object and click edit, you will go to /path/to/object/edit. /edit then gets recognised as a method alias, which points to the page template atct_edit, causing Zope to render /path/to/object/atct_edit.
Were you to define a custom edit form, you would do something like:
aliases = updateAliases(ATDocument,
{
'edit' : 'my_edit',
})
on your class. The utility method updateAliaes is defined in ATContentTypes/content/base.py.
Special targets
CMFDynamicViewFTI adds two special method alias targets:
- (selected layout)
- The method alias will resolve to the currently selected layout template, as chosen by the "display" menu. Note that this does not take into consideration any default-page content item chosen using the "Choose content item as default view" option in the
displaymenu. - (dynamic view)
- Is like
(selected layout), except it does take into consideration the default-page if one is selected.
You will notice that the (Default) method alias uses (dynamic view) as its target. This alias (which must be defined and capitalised exactly like that) defines what happens when you navigate directly to a content object without specifying a page template[1]. Hence, when you go to the url /path/to/object, it will look at the (Default) alias for the content type of object, and render the object with the chosen layout or default-page. This is also why the standard view action points to string:${object_url} only.
The view alias points to (selected layout) by convention. This is so that you can go to /path/to/folder/view to make sure you get the view of that folder, regardless of any selected default-page.
A note about file content
File content (files and images) need to dump their content to the browser when referenced directly. If you link to /path/to/image.jpg, it must render the image, not the image_view template for that object. This is achieved by pointing the (Default) alias to index_html, and defining a method index_html() on the file content type that dumps the content.
The /view alias can still be used to view the file within Plone. The view action must point to this method alias (string:${object_url}/view) instead of the more common (Default) alias (string:${object_url} only), or clicking the view tab would cause the file to dump its contents. Hence ATFileContent in ATContentTypes/content/base.py sets:
actions = updateActions(ATCTContent,
({
'id' : 'view',
'name' : 'View',
'action' : 'string:${object_url}/view',
'permissions' : (View,)
},
{
'id' : 'download',
'name' : 'Download',
'action' : 'string:${object_url}/download',
'permissions' : (View,),
'condition' : 'member', # don't show border for anon user
'visible' : False,
},
)
)
aliases = updateAliases(ATCTMixin,
{
'(Default)' : 'index_html',
'view' : '(selected layout)',
})
In certain places, it is important that Plone links to the /view alias to display the file inside Plone instead of dumping its contents. The property typesUseViewActionInListings in portal_properties/site_properties holds a list of these types. RichDocument's ImageAttachment and FileAttachment types, which simply extend ATImage and ATFile, must be registered here:
propsTool = getToolByName(context, 'portal_properties')
siteProperties = getattr(propsTool, 'site_properties')
typesUseViewActionInListings = list(siteProperties.getProperty('typesUseViewActionInListings'))
if 'ImageAttachment' not in typesUseViewActionInListings:
typesUseViewActionInListings.append('ImageAttachment')
siteProperties.manage_changeProperties(typesUseViewActionInListings = typesUseViewActionInListings)
[1] In previous versions of Plone and CMF, this used to result in a call to __call__(), which would look up the view action and generally make your life a misery if you were dealing with folders