Source code for plone.app.tiles.browser.traversal

from zope.interface import Interface, implements
from zope.component import queryMultiAdapter, queryUtility
from zope.component import getUtility

from zope.security import checkPermission
from zope.publisher.interfaces import IPublishTraverse
from zope.annotation.interfaces import IAnnotations

from plone.memoize.view import memoize
from plone.registry.interfaces import IRegistry
from plone.tiles.interfaces import ITileType
from plone.tiles.data import ANNOTATIONS_KEY_PREFIX

from plone.app.tiles.interfaces import ITileAddView, ITileEditView
from plone.app.tiles import MessageFactory as _


[docs]class TileTraverser(object): """Base class for tile add/edit view traversers. Below, we register two traversal views: ``@@add-tile`` and ``@@edit-tile``. """ targetInterface = Interface implements(IPublishTraverse) view = None def __init__(self, context, request): self.context = context self.request = request
[docs] def getTileViewByName(self, tile_name): """We look up for adapter from ``(context, request, tileType)`` to an appropriate interface. The default is to use the unnamed adapter, but this can be overridden by registering a named adapter with the name of the tile type. This way, a custom add/edit view can be reigstered for a particular type of tile. """ tile_info = queryUtility(ITileType, name=tile_name) if tile_info is None: raise KeyError(tile_name) view = queryMultiAdapter((self.context, self.request, tile_info), self.targetInterface, name=tile_name) if view is None: view = queryMultiAdapter((self.context, self.request, tile_info), self.targetInterface) if view is None: raise KeyError(tile_name) view.__name__ = tile_name view.__parent__ = self.context return view
[docs]class AddTile(TileTraverser): """Implements the @@add-tile traversal view Rendering this view on its own will display a template where the user may choose a tile type to add. Traversing to /path/to/obj/@@add-tile/tile-name will: * Look up the tile info for 'tile-name' as a named utility * Attempt to find view which is an adapter for (context, request, tile_info) with the name 'tile-name' * Fall back on the unnamed adapter of the same triple * Return above found view for rendering """ targetInterface = ITileAddView
[docs] def tileSortKey(self, type1, type2): return cmp(type1.title, type2.title)
@memoize
[docs] def tileTypes(self): """Get a list of addable ITileType objects representing tiles which are addable in the current context """ tiles = [] for tile_name in getUtility(IRegistry)['plone.app.tiles']: tiletype = getUtility(ITileType, tile_name) # check if we have permission to add this tile if checkPermission(tiletype.add_permission, self.context): # tile actions # TODO: read from registry tiletype.actions = [{ 'name': 'edit', 'url': '@@edit-tile', 'title': _('Edit'), }, { 'name': 'remove', 'url': '@@delete-tile', 'title': _('Remove'), }] tiles.append(tiletype) tiles.sort(self.tileSortKey) return tiles
def __call__(self): self.errors = {} self.request['disable_border'] = True if 'form.button.Create' in self.request: newTileType = self.request.get('tiletype', None) if newTileType is None: self.errors['tiletype'] = _(u"You must select the type of " + \ u"tile to create") if len(self.errors) == 0: self.request.response.redirect("%s/@@add-tile/%s" % \ (self.context.absolute_url(), newTileType)) return '' return self.index()
[docs] def publishTraverse(self, request, name): """Allow traversal to @@<view>/tilename """ # 1. Look up the view, but keep this view as the traversal context if self.view is None: self.view = self.getTileViewByName(name) return self.view raise KeyError(name)
[docs]class EditTile(TileTraverser): """Implements the @@edit-tile namespace. Traversing to /path/to/obj/@@edit-tile/tile-name/tile-id will: * Look up the tile info for 'tile-name' as a named utility * Attempt to find an adapter for (context, request, tile_info) with the name 'tile-name' * Fall back on the unnamed adapter of the same triple * Set the 'tileId' property on the view to the id 'tile-id * Return the view for rendering """ targetInterface = ITileEditView def __call__(self): raise KeyError("Please traverse to @@edit-tile/tilename/id")
[docs] def publishTraverse(self, request, name): """Allow traversal to @@<view>/tilename/tileid """ # 1. Look up the view, but keep this view as the traversal context in # anticipation of an id if self.view is None: self.view = self.getTileViewByName(name) return self # 2. Set the id and return the view we looked up in the previous # traversal step. elif getattr(self.view, 'tileId', None) is None: self.view.tileId = name return self.view raise KeyError(name)
[docs]class DeleteTile(TileTraverser): """Implements the @@delete-tile traversal view Traversing to /path/to/obj/@@delete-tile will list all tiles. Traversing to /path/to/obj/@@delete-tile/tile-id will delete tile. """ tileId = None def __init__(self, context, request): super(DeleteTile, self).__init__(context, request) self.annotations = IAnnotations(self.context) def __call__(self): self.deleted = False if self.tileId is not None: del self.annotations['%s.%s' % ( ANNOTATIONS_KEY_PREFIX, self.tileId)] return self.index()
[docs] def tiles(self): for item in self.annotations.keys(): if item.startswith(ANNOTATIONS_KEY_PREFIX): yield item[len(ANNOTATIONS_KEY_PREFIX) + 1:]
[docs] def publishTraverse(self, request, name): """Allow traversal to @@delete-tile/tilename """ if self.tileId is None: self.tileId = name return self