[Grok-dev] a "skin" keyword argument to view.url() method

Jan-Jaap Driessen janjaapdriessen at gmail.com
Tue Nov 20 11:14:27 UTC 2012


This is very useful to me too, but hey, we share a desk :)

+1


On Tue, Nov 20, 2012 at 11:33 AM, Jan-Wijbrand Kolman <janwijbrand at gmail.com
> wrote:

> Hi,
>
> In the application we develop we regularly need to compute URLs for a
> specific skin. We have some helper functions for that, but I guess
> having this functionality as part of the ``view.url()`` method could be
> generally useful.
>
> Below you will find a diff between the current grokcore.view trunk and
> the jw-urls-with-skin branch I created to implement this feature.
>
> Please tell me if you think this feature is indeed generally useful and
> whether you'd agree with my implementation. Thx!
>
> regards, jw
>
>
> Index: src/grokcore/view/util.py
> ===================================================================
> --- src/grokcore/view/util.py   (.../trunk)     (revision 128365)
> +++ src/grokcore/view/util.py   (.../branches/jw-urls-with-skin)
>  (revision
> 128365)
> @@ -14,18 +14,37 @@
>  """Grok utility functions.
>  """
>  import urllib
> +import urlparse
>  from grokcore.security.util import check_permission
>  from zope.component import getMultiAdapter
>  from zope.security.checker import NamesChecker, defineChecker
>  from zope.traversing.browser.absoluteurl import _safe as
> SAFE_URL_CHARACTERS
>  from zope.traversing.browser.interfaces import IAbsoluteURL
>
> +import directive
>
> -def url(request, obj, name=None, data=None):
> +ASIS = object()
> +
> +def url(request, obj, name=None, skin=ASIS, data=None):
>      url = getMultiAdapter((obj, request), IAbsoluteURL)()
>      if name is not None:
>          url += '/' + urllib.quote(name.encode('utf-8'),
> SAFE_URL_CHARACTERS)
>
> +    if skin is not ASIS:
> +        # Remove whatever ``++skin++[name]`` is active.
> +        parts = list(urlparse.urlparse(url))
> +        path = parts[2]
> +        if path.startswith('/++skin++'):
> +            # Find next / in the path.
> +            idx = path.find('/', 1)
> +            path = path[idx:]
> +        if skin is not None:
> +            # If a skin is set, add ``++skin++`` as the leading path
> segment.
> +            name = directive.skin.bind().get(skin)
> +            path = '/++skin++%s%s' % (name, path)
> +        parts[2] = path
> +        url = urlparse.urlunparse(parts)
> +
>      if not data:
>          return url
>
> Index: src/grokcore/view/ftests/url/url.py
> ===================================================================
> --- src/grokcore/view/ftests/url/url.py (.../trunk)     (revision 128365)
> +++ src/grokcore/view/ftests/url/url.py
> (.../branches/jw-urls-with-skin)        (revision 128365)
> @@ -171,6 +171,45 @@
>    >>> browser.contents
>    '11'
>
> +It is possible to compute URLs for specific skin names.
> +
> +First show how a view registered for a view, will by default compute URLs
> +for that skin:
> +
> +  >>>
> browser.open('http://127.0.0.1/++skin++urltesting/herd/manfred/@@test')
> +  >>> browser.contents
> +  "I'm on a url testing skin:
> +  http://127.0.0.1/++skin++urltesting/herd/manfred/test"
> +
> +We get the views manually so we can do a greater variety of url() calls:
> +
> +  >>> from zope.publisher.browser import applySkin
> +  >>> request = TestRequest()
> +  >>> applySkin(request, URLTestingSkin)
> +  >>> # Shifting names normally happens during URL traversal.
> +  >>> request._traversed_names = ['++skin++urltesting']
> +  >>> request.shiftNameToApplication()
> +  >>> index_view = component.getMultiAdapter((manfred, request),
> name='test')
> +  >>> index_view.url()
> +  'http://127.0.0.1/++skin++urltesting/herd/manfred/test'
> +
> +Explicitely remove the skin part:
> +
> +  >>> index_view.url(skin=None)
> +  'http://127.0.0.1/herd/manfred/test'
> +
> +Use another skin:
> +
> +  >>> index_view.url(skin=AnotherURLTestingSkin)
> +  'http://127.0.0.1/++skin++anotherurltesting/herd/manfred/test'
> +
> +Use something that is not a skin will fail:
> +
> +  >>> index_view.url(skin='foobar')
> +  Traceback (most recent call last):
> +  ...
> +  AttributeError: 'str' object has no attribute 'queryTaggedValue'
> +
>  """
>  import grokcore.view as grok
>  from zope.container.contained import Contained
> @@ -199,3 +238,16 @@
>          return unicode(self.age * 2)
>
>  yetanother = grok.PageTemplate('<p tal:replace="view/url" />')
> +
> +class URLTestingSkin(grok.IBrowserRequest):
> +    grok.skin('urltesting')
> +
> +class AnotherURLTestingSkin(grok.IBrowserRequest):
> +    grok.skin('anotherurltesting')
> +
> +class URLTestingViewOnASkin(grok.View):
> +    grok.layer(URLTestingSkin)
> +    grok.name('test')
> +
> +    def render(self):
> +        return u"I'm on a url testing skin: %s" % self.url()
> Index: src/grokcore/view/components.py
> ===================================================================
> --- src/grokcore/view/components.py     (.../trunk)     (revision 128365)
> +++ src/grokcore/view/components.py     (.../branches/jw-urls-with-skin)
> (revision 128365)
> @@ -78,7 +78,7 @@
>          return self.request.response.redirect(
>              url, status=status, trusted=trusted)
>
> -    def url(self, obj=None, name=None, data=None):
> +    def url(self, obj=None, name=None, skin=util.ASIS, data=None):
>          """Return string for the URL based on the obj and name.
>
>          If no arguments given, construct URL to view itself.
> @@ -91,6 +91,16 @@
>          If both object and name arguments are supplied, construct URL
>          to `obj/name`.
>
> +        Optionally pass a `skin` keyword argument. This should be a
> +        skin component and the skin's name is taken from this
> +        component. The effect of this argument is a leading
> +        ``++skin++[skinname]/`` segment in the path-part of the URL.
> +        When the argument is not passed, whatever skin is currently set
> +        on the request will be effective in the URL.
> +
> +        When passing ``None`` whatever skin is currently effective will
> +        be removed from the URLs.
> +
>          Optionally pass a `data` keyword argument which gets added to
>          the URL as a CGI query string.
>
> @@ -110,7 +120,7 @@
>              # create URL to view on context
>              obj = self.context
>
> -        return util.url(self.request, obj, name, data)
> +        return util.url(self.request, obj, name, skin, data)
>
>
> _______________________________________________
> Grok-dev mailing list
> Grok-dev at zope.org
> https://mail.zope.org/mailman/listinfo/grok-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.zope.org/pipermail/grok-dev/attachments/20121120/7edcf4da/attachment.html>


More information about the Grok-dev mailing list