source: main/waeup.ikoba/trunk/src/waeup/ikoba/doctests/breadcrumbs.txt @ 14022

Last change on this file since 14022 was 12989, checked in by Henrik Bettermann, 9 years ago

Move doctests.

File size: 7.6 KB
Line 
1Breadcrumbs
2***********
3
4We use an adapter approach to get a flexible system of creating and
5retrieving breadcrumbs for certain views.
6
7
8How to get existing breadcrumbs
9===============================
10
11We create a company to check the breadcrumb functionality.
12
13    >>> from waeup.ikoba.app import Company
14    >>> root = getRootFolder()
15    >>> root['app'] = Company()
16    >>> app = root['app']
17
18The quick way (if you have a viewname)
19--------------------------------------
20
21We can get an ordered list of breadcrumbs for a given context and
22viewname:
23
24    >>> from waeup.ikoba.browser.breadcrumbs import getBreadcrumbList
25    >>> blist1 = getBreadcrumbList(app, 'index')
26    >>> blist1
27    [<waeup.ikoba.browser.breadcrumbs.CompanyBreadcrumb object at 0x...>]
28
29A slightly more extensive list for the datacenter:
30
31    >>> blist2 = getBreadcrumbList(app['datacenter'], 'index')
32    >>> from pprint import pprint
33    >>> pprint(blist2)
34    [<waeup.ikoba.browser.breadcrumbs.CompanyBreadcrumb object at 0x...>,
35     <waeup.ikoba.browser.breadcrumbs.AdministrationBreadcrumb object at 0x...>,
36     <waeup.ikoba.browser.breadcrumbs.DataCenterBreadcrumb object at 0x...>]
37
38We get a breadcrumb for company, administration area and data
39center in that order.
40
41Each breadcrumb provides a ``title``, ``context``, and ``viewname``
42attribute, so that views and page templates can easily create markup
43out of it:
44
45     >>> pprint([(x.title) for x in blist2])
46     [u'Home', u'Administration', u'Data Center']
47
48     >>> pprint([(x.context, x.viewname) for x in blist2])
49     [(<waeup.ikoba.app.Company object at 0x...>, 'index'),
50      (<waeup.ikoba.app.Company object at 0x...>, 'administration'),
51      (<waeup.ikoba.datacenter.DataCenter object at 0x...>, 'index')]
52
53The administration area breadcrumb might be a surprise, as there is no
54equivalent object in the ZODB. In fact the administration area is only
55a certain view (the 'administration' view) on the company object.
56
57We will show below, how you can define breadcrumbs this way.
58
59As a rule of thumb you should know, that every breadcrumb is not only
60attached for a certain kind of object, but for a tuple of context
61object and a viewname.
62
63This way we can make sure, that there are different breadcrumb lists
64generated for instance for the administration view of Company
65instances and the index view. While the first should look something
66like::
67
68  Home -> Administration
69
70we expect for the latter only::
71
72  Home
73
74
75Another quick way (if you have a complete view)
76-----------------------------------------------
77
78Another quick approach for use in viewlets, views and similar
79contexts, where you usually have a view available but not a viewname,
80is to use ``getBreadcrumbListForView``.
81
82We create a view (a page in this case, but pages are views) on the
83user administration index page:
84
85    >>> from zope.publisher.browser import TestRequest
86    >>> from zope.component import getMultiAdapter
87    >>> page = getMultiAdapter((app['users'], TestRequest()), name='index')
88
89Now we can get the breadcrumbs for this view:
90
91    >>> from waeup.ikoba.browser.breadcrumbs import getBreadcrumbListForView
92    >>> blist3 = getBreadcrumbListForView(page)
93    >>> [x.title for x in blist3]
94    [u'Home', u'Administration', u'Officers']
95
96..note:: This works only for views created with grokcore.component
97         (i.e. Grok Views, Pages, etc.) but not for simple Zope3
98         views, as the viewname can not easily be extracted from the
99         view for the latter ones.
100
101
102Type-safe retrieval of breadcrumbs for a view
103---------------------------------------------
104
105If you want to make sure, that a view for which you want to get
106breadcrumbs is really a Grok view, then you can use the
107IBreadcrumbContainer adapter. This one adapts only grok views.
108
109The returned breadcrumb container supports iteration:
110
111    >>> from waeup.ikoba.browser.interfaces import IBreadcrumbContainer
112    >>> mybccontainer = IBreadcrumbContainer(page)
113    >>> [x.title for x in mybccontainer]
114    [u'Home', u'Administration', u'Officers']
115
116It is, however, not a real Python list but only an iterable
117container. You can also get the real list of breadcrumbs:
118
119    >>> pprint(mybccontainer.getList())
120    [<...breadcrumbs.CompanyBreadcrumb object at 0x...>,
121     <...breadcrumbs.AdministrationBreadcrumb object at 0x...>,
122     <...breadcrumbs.UsersContainerBreadcrumb object at 0x...>]
123
124
125
126The general details
127-------------------
128
129Now we can get breadcrumbs for contexts and view names. For example a
130breadcrumb for the 'index' view of our Company object:
131
132    >>> from zope.component import getAdapter
133    >>> from waeup.ikoba.browser.interfaces import IBreadcrumb
134    >>> b1 = getAdapter(app, IBreadcrumb, 'index')
135    >>> b1
136    <waeup.ikoba.browser.breadcrumbs.CompanyBreadcrumb object at 0x...>
137
138Breadcrumb objects provide a title:
139
140    >>> b1.title
141    u'Home'
142
143a parent (None for the app object):
144
145    >>> b1.parent is None
146    True
147
148and a viewname:
149
150    >>> b1.viewname
151    'index'
152
153Using a context and a viewname, one can easily compute a complete URL
154in views, viewlets, etc.
155
156    >>> b2 = getAdapter(app['datacenter'], IBreadcrumb, 'index')
157    >>> b2
158    <waeup.ikoba.browser.breadcrumbs.DataCenterBreadcrumb object at 0x...>
159
160    >>> b2.title
161    u'Data Center'
162
163    >>> b2.viewname
164    'index'
165
166As the data center is not root of the hierarchy, it provides a
167non-trivial parent:
168
169    >>> b2.parent
170    (<waeup.ikoba.app.Company object at 0x...>, 'administration')
171
172This result denotes a new context object (the Company instance we
173created above) and a view name ('administration').
174
175Normally, the view name would be 'index', but as some administrative
176components should look to the user as if they were grouped in a common
177subarea of the root (the administration area), we can also set a
178different view than the default as target.
179
180When we like to receive the breadcrumb for this parent, we can do so
181as above:
182
183    >>> context, viewname = b2.parent
184    >>> b3 = getAdapter(context, IBreadcrumb, viewname)
185    >>> b3
186    <waeup.ikoba...breadcrumbs.AdministrationBreadcrumb object at 0x...>
187
188As you can see, we get an AdministrationBreadcrumb, although the
189context object, for which the breadcrumb was created is also the
190Company instance as above:
191
192    >>> b3.context is b1.context
193    True
194
195This administration area now has still a parent, the front-page:
196
197    >>> context, viewname = b3.parent
198    >>> context, viewname
199    (<waeup.ikoba.app.Company object at 0x...>, 'index')
200
201We create last breadcrumb:
202
203    >>> b4 = getAdapter(context, IBreadcrumb, viewname)
204
205This is finally the last piece, the breadcrumb which links to the
206front page. It has no parent:
207
208    >>> b4.parent is None
209    True
210
211
212How to create new breadcrumbs
213=============================
214
215Breadcrumbs are looked up as named adapters. This means, you must
216create a named adapter with the following specifications:
217
218 * Derive your breadcrumb class from ``Breadcrumb`` class. This will
219   save you lots of work.
220
221 * The adapter context (``grok.context``) must be the object type you
222   want to provide a breadcrumb for. So, if you want to write a
223   Breadcrumb adapter for objects providing ``IMyFunnyType``, write::
224
225     grok.context(IMyFunnyType)
226
227 * The adapter name (``grok.name``) must be the same as the name of
228   the view, for which the breadcrumb component should be
229   registered.
230
231   If you want to write a breadcrumb component for the 'index' view of
232   some content type and derive your class from Breadcrumb, then you
233   can skip this step as 'index' is the default name.
234
235 * Set a ``title`` attribute to give the text that should be
236   displayed. Use something like::
237
238     @property
239     def title(self):
240       return self.some_computed_title()
241
242   if you want computed titles.
243
Note: See TracBrowser for help on using the repository browser.