Adding Actions/Views to Content Objects
In Plone, each object has a number of applicable actions which link to views. These are normally seen in the Plone User Interface as tabs such as "contents", "view", "edit", "references" and "properties". You can read a general background on the use of Actions in The Plone Book, Chapter 5. As a developer, you can define new, custom actions for your Product's data-types which, when registered with the system, will appear in the standard action tabs.
gmane :
From: Mike C. Fletcher <mcfletch@...> Subject: Developing views/actions for Plone, request for review Date: Mon, 26 Apr 2004 03:00:48 +0000 I've been pulling together various documents describing the process of attaching actions/views to Plone objects (targeted at Python developers). The document is still quite preliminary, I'm mostly looking for clarification and/or comments (particularly for those areas marked with XXX in the text). Have fun all, Mike
Adding Actions/Views to Content Objects
In Plone, each object has a number of applicable actions which link to views. These are normally seen in the Plone User Interface as tabs such as "contents", "view", "edit", "references" and "properties". You can read a general background on the use of Actions in The Plone Book, Chapter 5. As a developer, you can define new, custom actions for your Product's data-types which, when registered with the system, will appear in the standard action tabs.
Actions are registered for Archetypes objects by the product's installation script (external method) as part of the "factory type information" (XXX link) describing the object. As a result, if you alter the set of actions for your already-installed object you will need to uninstall and reinstall the Product before you will see the new action in the user interface.
Custom actions are specified as a sequence of dictionaries in the class-attribute "actions". Each dictionary describes a particular action like so (XXX is this the sole best-practices approach? certain modules include a factory_types_information attribute in the module with all of this information embedded there instead. Which is preferable (I would assume the direct-on-class approach)?):
class Task(public.BaseContent):
"""A Simplified Task/Todo Item"""
actions = ({
'id':'alltasks',
'name':'All Tasks',
'action' : 'alltasks',
'permissions' : (CMFCorePermissions.View,),
},)
The dictionaries are passed as parameters to ActionProviderBase.addAction, which creates ActionInformation instances from them. The parameters available for the dictionaries are as follows (XXX the properties are covered in Chapter 5 of the Plone book, but without much information regarding choices to make while authoring them):
- id -- the ID for the action, required, must be unique within the tool provider (XXX which is the product in this instance?)
- name -- the name/title for the ActionInformation (stored as title in the ActionInformation instance), required. This is the string used in the UI to describe the action. (XXX internationalising it)
- action -- string representing a Zope Page Template
expression to be evaluated to generate the URL for the
action. If the string does not start with
string:orpython:it will be substituted into the expressionstring:${object_url}/%s, as would be done with the example above. More complex examples would include:string:${object_url}/mailboxer_viewstring:${portal_url}/administrate_currencies- XXX find out what the execution environment is so that we can instead document what is available to make decisions
- condition -- string representing a Zope Page Template
expression to be evaluated to determine whether the
action is available to the user. Examples include:
member(only visible to members)python: not object.isCheckedOut()python: object.displayContentsTab()python: object and portal.portal_workflow.getTransitionsFor(object, object.getParentNode())python: portal.portal_membership.checkPermission("Delete objects", object)python: portal.portal_membership.getMembersFolder()python: folder.displayContentsTab()python: member and folder is not object and object.displayContentsTab()python: folder is object and portal.portal_syndication.isSiteSyndicationAllowed()- XXX find out what the execution environment is so that we can instead document all possibilities
- permission -- tuple of permissions (strings (or a
single permission string)) which is/are required to
access the action; if the permissions are not available,
the action will not appear in the UI.
- Note: this does not set permissions for the referenced view! It just determines the permission for the action.
- category -- (functional default of "object") seperates
views into categories within the UI, common categories
include:
object-- actions in this category appear on objectsfolder-- actions in this category appear on foldersuser-- are actions that relate to a user, such as "Log in" and "Join"object_tabs-- these actions appear in the middle of the page at the top of the content. These actions are usually related to the content, in many cases they do not show up unless the current user has the right to edit the content.folder_buttons-- are the buttons that appear on the folder contents page and relate to copying or moving content in a folder, such as copy and paste.portal_tabs-- these actions appear at the very top of the Plone site the default ones are "Welcome", "Members", "News", "Search" and so on. Actions in this category are normally related to the entire portal, as opposed to particular content.document_actionsProductssite_actionsglobalworkflow- XXX documentation for all of the above needed from a developer's standpoint, when would you define each type, for what purpose, and what contract does the linked view need to support
- XXX determine if the last 5 items are actually intended to be used by end-developers
- visible -- boolean determining whether the action is
visible in the User Interface or not
- XXX note that the Plone book says this applies to the category, not the view somehow?
Now, to make the action links work, we need to put something at the location specified by the "action" expression, the view. As we've seen above, the URL specified by the action can be entirely arbitrary, so it can point to any page in the site. However, the most common case is where we would like to attach a particular view to our content objects, for instance to provide an alternate presentation of the object's data.
For example, this sample code defines a page-template view which is pointed to by the action in the example above:
class Task(public.BaseContent):
"""A Simplified Task/Todo Item"""
security = ClassSecurityInfo()
security.declareProtected( CMFCorePermissions.View, 'alltasks' )
alltasks = PageTemplateFile.PageTemplateFile(
'www/alltasks.html',
globals()
)
This view is protected with the (very broad) "View"
permission, the same as the action associated with it. It
is available as a sub-object of the Task object, which
matches the definition in the Action (if you will recall
the "action" field of the the action object expands tothe
TAL expression string:${object_url}/alltasks). (XXX link
to discussion of creating executable content types).
- XXX Discussion the portal_actions tool, and its
ability to alter the installed actions.
- XXX Discuss action_providers tab, and how content-registered actions interact (do they? don't appear to)
- XXX Discuss whether un-install/re-install resets customised portal_actions
- XXX Best practices for multi-object views such as
"alltasks" in the example code, likely use the default
calendar as an exemplar?
- Should these be installed as tools/portal views?
- XXX Links to Zope Page Template expression summary
- XXX Discuss the folder/object distinction as to when a developer should choose one versus the other and what the difference is in terms of execution environment (if any)
- XXX Discuss hiding views for certain classes of user (use permissions)
- XXX Discuss appropriate use of invisible views (which is???)
- XXX Discuss use of modify_fti to change actions, why use this instead of just directly specifying the desired values?






