The existing two absolute_url adapter implementations are specifically geared

towards OFS.Traversable and OFS.Application. Name them so.

Introduce a more generic implementation that's very very close to the Zope 3
one and works on objects that don't inherit from OFS.Traversable or support
acquisition (e.g. views, resources, etc.)
parent 2001fb27
...@@ -15,24 +15,87 @@ ...@@ -15,24 +15,87 @@
$Id$ $Id$
""" """
import urllib
from Acquisition import aq_inner, aq_parent from Acquisition import aq_inner, aq_parent
from OFS.interfaces import ITraversable from OFS.interfaces import ITraversable
from zope.interface import implements from zope.interface import implements
from zope.component import getMultiAdapter from zope.component import getMultiAdapter
from zope.traversing.browser.interfaces import IAbsoluteURL from zope.traversing.browser.interfaces import IAbsoluteURL
from zope.traversing.browser.absoluteurl import _insufficientContext, _safe
from Products.Five.browser import BrowserView from Products.Five.browser import BrowserView
class AbsoluteURL(BrowserView): class AbsoluteURL(BrowserView):
"""An adapter for Zope3-style absolute_url using Zope2 methods """An absolute_url adapter for generic objects in Zope 2 that
aren't OFS.Traversable (e.g. views, resources, etc.).
(original: zope.traversing.browser.absoluteurl) This is very close to the generic implementation from
zope.traversing.browser, but the Zope 2 request doesn't support
all the methods that it uses yet.
""" """
implements(IAbsoluteURL) implements(IAbsoluteURL)
def __init__(self, context, request): def __unicode__(self):
self.context, self.request = context, request return urllib.unquote(self.__str__()).decode('utf-8')
def __str__(self):
context = self.context
request = self.request
container = aq_parent(context)
if container is None:
raise TypeError(_insufficientContext)
url = str(getMultiAdapter((container, request), name='absolute_url'))
name = self._getContextName(context)
if name is None:
raise TypeError(_insufficientContext)
if name:
url += '/' + urllib.quote(name.encode('utf-8'), _safe)
return url
__call__ = __str__
def _getContextName(self, context):
if getattr(context, 'getId', None) is not None:
return context.getId()
getattr(context, '__name__', None)
def breadcrumbs(self):
context = self.context
request = self.request
# We do this here do maintain the rule that we must be wrapped
container = aq_parent(context)
if container is None:
raise TypeError(_insufficientContext)
base = tuple(getMultiAdapter((container, request),
name='absolute_url').breadcrumbs())
name = self._getContextName(context)
if name is None:
raise TypeError(_insufficientContext)
if name:
base += ({'name': name,
'url': ("%s/%s" % (base[-1]['url'],
urllib.quote(name.encode('utf-8'),
_safe)))
}, )
return base
class OFSTraversableAbsoluteURL(BrowserView):
"""An absolute_url adapter for OFS.Traversable subclasses
"""
implements(IAbsoluteURL)
def __unicode__(self):
return urllib.unquote(self.__str__()).decode('utf-8')
def __str__(self): def __str__(self):
context = aq_inner(self.context) context = aq_inner(self.context)
...@@ -47,10 +110,10 @@ class AbsoluteURL(BrowserView): ...@@ -47,10 +110,10 @@ class AbsoluteURL(BrowserView):
name = context.getId() name = context.getId()
if container is None or self._isVirtualHostRoot() \ if (container is None
or not ITraversable.providedBy(container): or self._isVirtualHostRoot()
return ( or not ITraversable.providedBy(container)):
{'name': name, 'url': context.absolute_url()},) return ({'name': name, 'url': context.absolute_url()},)
view = getMultiAdapter((container, request), IAbsoluteURL) view = getMultiAdapter((container, request), IAbsoluteURL)
base = tuple(view.breadcrumbs()) base = tuple(view.breadcrumbs())
...@@ -66,15 +129,9 @@ class AbsoluteURL(BrowserView): ...@@ -66,15 +129,9 @@ class AbsoluteURL(BrowserView):
context = aq_inner(self.context) context = aq_inner(self.context)
return context.restrictedTraverse(virtualrootpath) == context return context.restrictedTraverse(virtualrootpath) == context
class SiteAbsoluteURL(AbsoluteURL): class RootAbsoluteURL(OFSTraversableAbsoluteURL):
"""An adapter for Zope3-style absolute_url using Zope2 methods """An absolute_url adapter for the root object (OFS.Application)
This one is just used to stop breadcrumbs from crumbing up
to the Zope root.
(original: zope.traversing.browser.absoluteurl)
""" """
def breadcrumbs(self): def breadcrumbs(self):
context = self.context context = self.context
request = self.request request = self.request
......
...@@ -39,16 +39,32 @@ ...@@ -39,16 +39,32 @@
/> />
<browser:page <browser:page
for="zope.traversing.interfaces.IContainmentRoot" for="OFS.interfaces.ITraversable"
name="absolute_url" name="absolute_url"
class=".absoluteurl.SiteAbsoluteURL" class=".absoluteurl.OFSTraversableAbsoluteURL"
permission="zope.Public" permission="zope.Public"
allowed_interface="zope.traversing.browser.interfaces.IAbsoluteURL" allowed_interface="zope.traversing.browser.interfaces.IAbsoluteURL"
/> />
<view <view
for="zope.traversing.interfaces.IContainmentRoot" for="OFS.interfaces.ITraversable"
factory=".absoluteurl.SiteAbsoluteURL" factory=".absoluteurl.OFSTraversableAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="OFS.interfaces.IApplication"
name="absolute_url"
class=".absoluteurl.RootAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="OFS.interfaces.IApplication"
factory=".absoluteurl.RootAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest" type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public" permission="zope.Public"
provides="zope.traversing.browser.interfaces.IAbsoluteURL" provides="zope.traversing.browser.interfaces.IAbsoluteURL"
......
...@@ -51,12 +51,11 @@ def test_absoluteurl(): ...@@ -51,12 +51,11 @@ def test_absoluteurl():
This test assures and demonstrates that the absolute url stops This test assures and demonstrates that the absolute url stops
traversing through an object's parents when it has reached the traversing through an object's parents when it has reached the
root object. In Zope 3 this is marked with the IContainmentRoot root object.
interface:
>>> from zope.interface import directlyProvides, providedBy >>> from zope.interface import alsoProvides, noLongerProvides
>>> from zope.traversing.interfaces import IContainmentRoot >>> from OFS.interfaces import IApplication
>>> directlyProvides(self.folder, IContainmentRoot) >>> alsoProvides(self.folder, IApplication)
>>> for crumb in view.breadcrumbs(): >>> for crumb in view.breadcrumbs():
... info = crumb.items() ... info = crumb.items()
...@@ -65,8 +64,7 @@ def test_absoluteurl(): ...@@ -65,8 +64,7 @@ def test_absoluteurl():
[('name', 'test_folder_1_'), ('url', 'http://nohost/test_folder_1_')] [('name', 'test_folder_1_'), ('url', 'http://nohost/test_folder_1_')]
[('name', 'testoid'), ('url', 'http://nohost/test_folder_1_/testoid')] [('name', 'testoid'), ('url', 'http://nohost/test_folder_1_/testoid')]
>>> directlyProvides(self.folder, >>> noLongerProvides(self.folder, IApplication)
... providedBy(self.folder) - IContainmentRoot)
The absolute url view is obviously not affected by virtual hosting: The absolute url view is obviously not affected by virtual hosting:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment