Home Company Services Portfolio Contact us nav spacer

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: or python: it will be substituted into the expression string:${object_url}/%s, as would be done with the example above. More complex examples would include:
    • string:${object_url}/mailboxer_view
    • string:${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 objects
    • folder -- actions in this category appear on folders
    • user -- 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_actions
    • Products
    • site_actions
    • global
    • workflow
    • 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?