Example #1
0
    def makeBreadcrumbForRequestedPage(self):
        """Return an `IBreadcrumb` for the requested page.

        The `IBreadcrumb` for the requested page is created using the current
        URL and the page's name (i.e. the last path segment of the URL).

        If the requested page (as specified in self.request) is the default
        one for our parent view's context, return None.
        """
        url = self.request.getURL()
        obj = self.request.traversed_objects[-2]
        default_view_name = getDefaultViewName(obj, self.request)
        view = self._naked_context_view
        if view.__name__ != default_view_name:
            title = getattr(view, 'page_title', None)
            if title is None:
                title = getattr(view, 'label', None)
            if isinstance(title, Message):
                title = i18n.translate(title, context=self.request)
            breadcrumb = Breadcrumb(None)
            breadcrumb._url = url
            breadcrumb.text = title
            return breadcrumb
        else:
            return None
 def test_url(self):
     # The detail properted is the _detail attribute or the text attribute.
     cookbook = Cookbook()
     breadcrumb = Breadcrumb(cookbook)
     breadcrumb._url = '/hello'
     self.assertEqual('/hello', breadcrumb.url)
     breadcrumb._url = None
     self.assertEqual('http://launchpad.dev/cookbook', breadcrumb.url)
 def test_detail(self):
     # The detail properted is the _detail attribute or the text attribute.
     cookbook = Cookbook()
     breadcrumb = Breadcrumb(cookbook)
     breadcrumb._detail = 'hello'
     breadcrumb.text = 'goodbye'
     self.assertEqual('hello', breadcrumb.detail)
     breadcrumb._detail = None
     self.assertEqual('goodbye', breadcrumb.detail)
Example #4
0
    def makeBreadcrumbsForRequestedPage(self):
        """Return a sequence of `IBreadcrumb`s for the requested page.

        The `IBreadcrumb` for the requested page is created using the current
        URL and the page's name (i.e. the last path segment of the URL).

        If the view is the default one for the object or the current
        facet, no breadcrumbs are returned -- we'll have injected a
        facet Breadcrumb earlier in the hierarchy which links here.
        """
        url = self.request.getURL()
        obj = self.request.traversed_objects[-2]
        default_view_name = getDefaultViewName(obj, self.request)
        view = self._naked_context_view
        default_views = [default_view_name]
        facet = queryUtility(IFacet, name=get_facet(view))
        if facet is not None:
            default_views.append(facet.default_view)
        crumbs = []

        # Views may provide an additional breadcrumb to precede them.
        # This is useful to have an add view link back to its
        # collection despite its parent being the context of the collection.
        if hasattr(view, 'inside_breadcrumb'):
            crumbs.append(view.inside_breadcrumb)

        if hasattr(view, '__name__') and view.__name__ not in default_views:
            title = getattr(view, 'page_title', None)
            if title is None:
                title = getattr(view, 'label', None)
            if isinstance(title, Message):
                title = i18n.translate(title, context=self.request)
            crumbs.append(Breadcrumb(None, url=url, text=title))
        return crumbs
Example #5
0
    def items(self):
        """Return a list of `IBreadcrumb` objects visible in the hierarchy.

        The list starts with the breadcrumb closest to the hierarchy root.
        """
        breadcrumbs = []
        for obj in self.objects:
            breadcrumb = IBreadcrumb(obj, None)
            if breadcrumb is not None:
                breadcrumbs.append(breadcrumb)

        facet = queryUtility(IFacet, name=get_facet(self._naked_context_view))
        if breadcrumbs and facet is not None:
            # We have breadcrumbs and we're on a custom facet, so we'll
            # sneak an extra breadcrumb for the facet we're on.
            # Iterate over the context of our breadcrumbs in reverse order and
            # find the first one that implements IMultiFactedBreadcrumb.
            # It'll be facet-agnostic, so insert a facet-specific one
            # after it.
            for idx, breadcrumb in reversed(list(enumerate(breadcrumbs))):
                if IMultiFacetedBreadcrumb.providedBy(breadcrumb):
                    facet_crumb = Breadcrumb(
                        breadcrumb.context, rootsite=facet.rootsite,
                        text=facet.text)
                    alsoProvides(facet_crumb, IFacetBreadcrumb)
                    breadcrumbs.insert(idx + 1, facet_crumb)
                    # Ensure that all remaining breadcrumbs are
                    # themselves faceted.
                    for remaining_crumb in breadcrumbs[idx + 1:]:
                        remaining_crumb.rootsite_override = facet.rootsite
                    break
        if len(breadcrumbs) > 0:
            breadcrumbs.extend(self.makeBreadcrumbsForRequestedPage())
        return breadcrumbs
Example #6
0
 def inside(self):
     return Breadcrumb(self.context.owner,
                       url=canonical_url(self.context.owner,
                                         view_name="+recipes",
                                         rootsite="code"),
                       text="Recipes",
                       inside=self.context.owner)
 def test_init_without_params(self):
     # The attributes are None by default.
     cookbook = Cookbook()
     breadcrumb = Breadcrumb(cookbook)
     self.assertIs(None, breadcrumb.text)
     self.assertIs(None, breadcrumb._detail)
     self.assertIs(None, breadcrumb._url)
 def test_init_with_params(self):
     cookbook = Cookbook()
     breadcrumb = Breadcrumb(
         cookbook, url='http://example.com', text="Example")
     self.assertIs('Example', breadcrumb.text)
     self.assertIs('http://example.com', breadcrumb._url)
     self.assertIs(None, breadcrumb._detail)
Example #9
0
 def inside(self):
     return Breadcrumb(
         self.context.owner,
         url=canonical_url(self.context.owner, view_name="+snaps"),
         text="Snap packages", inside=self.context.owner)
Example #10
0
    def _publishTraverse(self, request, name):
        """Traverse, like zope wants."""

        # First, set a new layer if there is one.  This is important to do
        # first so that if there's an error, we get the error page for
        # this request.
        if self.newlayer is not None:
            setFirstLayer(request, self.newlayer)

        # Next, see if we're being asked to stepto somewhere.
        stepto_traversals = self.stepto_traversals
        if stepto_traversals is not None:
            if name in stepto_traversals:
                handler = stepto_traversals[name]
                try:
                    nextobj = handler(self)
                except NotFoundError:
                    nextobj = None

                return self._handle_next_object(nextobj, request, name)

        # Next, see if we have at least two path steps in total to traverse;
        # that is, the current name and one on the request's traversal stack.
        # If so, see if the name is in the namespace_traversals, and if so,
        # dispatch to the appropriate function.  We can optimise by changing
        # the order of these checks around a bit.
        # If the next path step is a zope namespace eg ++model++, then we
        # actually do not want to process the path steps as a stepthrough
        # traversal so we just ignore it here.
        namespace_traversals = self.stepthrough_traversals
        if namespace_traversals is not None:
            if name in namespace_traversals:
                stepstogo = request.stepstogo
                if stepstogo:
                    # First peek at the nextstep to see if we should ignore it.
                    nextstep = stepstogo.peek()
                    if not RESERVED_NAMESPACE.match(nextstep):
                        nextstep = stepstogo.consume()
                        handler = namespace_traversals[name]
                        try:
                            nextobj = handler(self, nextstep)
                        except NotFoundError:
                            nextobj = None
                        else:
                            # Circular import; breaks make.
                            from lp.services.webapp.breadcrumb import (
                                Breadcrumb,
                            )
                            stepthrough_page = queryMultiAdapter(
                                    (self.context, self.request), name=name)
                            if stepthrough_page:
                                # Not all stepthroughs have a page; if they
                                # don't, there's no need for a breadcrumb.
                                page_title = getattr(
                                    stepthrough_page, 'page_title', None)
                                label = getattr(
                                    stepthrough_page, 'label', None)
                                stepthrough_text = page_title or label
                                if isinstance(stepthrough_text, Message):
                                    stepthrough_text = i18n.translate(
                                        stepthrough_text,
                                        context=self.request)
                                stepthrough_url = canonical_url(
                                    self.context, view_name=name)
                                stepthrough_breadcrumb = Breadcrumb(
                                    context=self.context,
                                    url=stepthrough_url,
                                    text=stepthrough_text)
                                self.request.traversed_objects.append(
                                    stepthrough_breadcrumb)

                        return self._handle_next_object(nextobj, request,
                            nextstep)

        # Next, look up views on the context object.  If a view exists,
        # use it.
        view = queryMultiAdapter((self.context, request), name=name)
        if view is not None:
            return view

        # Next, look up redirections.  Note that registered views take
        # priority over redirections, because you can always make your
        # view redirect, but you can't make your redirection 'view'.
        redirections = self.redirections
        if redirections is not None:
            if name in redirections:
                urlto, status = redirections[name]
                return RedirectionView(urlto(self), request, status=status)

        # Finally, use the self.traverse() method.  This can return
        # an object to be traversed, or raise NotFoundError.  It must not
        # return None.
        try:
            nextobj = self.traverse(name)
        except NotFoundError:
            nextobj = None
        return self._handle_next_object(nextobj, request, name)
Example #11
0
 def inside(self):
     return Breadcrumb(self.context.pillar,
                       url=canonical_url(self.context.pillar,
                                         view_name="+sharing"),
                       text="Sharing",
                       inside=self.context.pillar)
 def test_urldata_rootsite_is_honored(self):
     # When a class' ICanonicalUrlData defines a rootsite, our Breadcrumb
     # adapter will use it.
     cookbook = Cookbook()
     cookbook.rootsite = 'cooking'
     self.assertEqual(Breadcrumb(cookbook).rootsite, 'cooking')
 def test_rootsite_defaults_to_mainsite(self):
     # When a class' ICanonicalUrlData doesn't define a rootsite, our
     # Breadcrumb adapter will use 'mainsite' as the rootsite.
     cookbook = Cookbook()
     self.assertIs(cookbook.rootsite, None)
     self.assertEqual(Breadcrumb(cookbook).rootsite, 'mainsite')
Example #14
0
 def inside(self):
     return Breadcrumb(self.context.owner,
                       url=canonical_url(self.context.owner,
                                         view_name="+livefs"),
                       text="Live filesystems",
                       inside=self.context.owner)