1 # -*- coding: iso-8859-1 -*-
3 MoinMoin - macro to collect data from definition lists from pages
4 into a databrowser widget table
7 will create a on default a table row for every subpage of the current page
8 and a table column for each key and fills the cells with data from each
9 key value pair of a definition list. You can change the search_expression
10 keyword to any regex you want. All attributes to the macro are optional.
11 You can give as an attribute to the macro the name of the template page
12 the definition list page depends on.
13 You can also list the desired keys with the attribute column_heading.
14 In the latter case the table colunms will have the same order as the keys
16 The macro can finally also use the definition list from another pagename.
17 By setting a parser one can use a different parser than moinmoin's default
18 like for example wikimarkup.
19 With the attribute filter_selection you can use the filter method of the
20 databrowser widget (this needs javascript enabled).
21 By using a different filter_column_value than the default empty one,
22 eg. name:: Cohen you get only rows shown where that name was found.
23 If you want to rename your column titles later on that can be done
24 by adding the dictionary keyword pointing on a page with aliases
25 for your labels as definition list.
26 With sort_column_name given as list you can sort the table by
27 multiple columns. And sort_reverse=True makes it reverse.
28 By using the keyword transpose the table is shown transposed.
29 Until transpose is not part of the databrowser widget itselfs we
30 don't support every feature of this macro e.g. filter_selection.
32 <<CollectLists(search_expression=regex:title:^Examplepage/)>
34 @copyright: 2006 by michael cohen <scudette@users.sourceforge.net> (PageDicts)
36 @license: GNU GPL, see COPYING for details.
39 from decimal import Decimal, InvalidOperation
40 from MoinMoin import wikiutil, search
41 from MoinMoin.Page import Page
42 from MoinMoin.util.dataset import TupleDataset, Column
43 from MoinMoin.widget.browser import DataBrowserWidget
45 Dependencies = ["pages"]
47 # Using old or new dict engine depending on version.
49 from MoinMoin.wikidicts import Dict
51 def get_dict(request, dict_source):
52 return Dict(request, dict_source)
54 def get_dict(request, dict_source):
55 return request.dicts[dict_source]
57 def sort_table(table, cols=0, reverse=False):
59 sorts by column number. If a list is given multiple columns become sorted
61 for col in reversed(cols):
62 table = sorted(table, key=operator.itemgetter(col), reverse=reverse)
65 def table2rows(table):
67 transforms a data.data table of widget data browser into an array of lists without tuples
73 if isinstance(element, tuple):
75 tmp.append(Decimal(element[1]))
76 except InvalidOperation:
77 tmp.append(element[1])
80 tmp.append(Decimal(element))
81 except InvalidOperation:
88 transforms an array of lists into an array of lists with tuples compatible to widget data browser data.data
92 tmp = [(str(element), str(element)) for element in line]
93 table_data.append(tmp)
97 def macro_CollectLists(macro, pagename=unicode,
98 align=("left", "center", "right"),
103 filter_column_value=u'',
104 sort_column_name=u'',
106 parser=u'text_moin_wiki',
107 search_expression=None,
108 filter_selection=u'NeverExistingDefaultFilter'):
111 currently we don't support transpose together with filter_selection
113 request = macro.request
114 formatter = macro.formatter
118 WikiParser = wikiutil.importPlugin(request.cfg, 'parser', parser, function="Parser")
119 except wikiutil.PluginMissingError:
123 pagename = formatter.page.page_name
125 if filter_column_value and ':: ' in filter_column_value:
126 filter_key, filter_word = filter_column_value.split('::')
127 filter_key = filter_key.strip()
128 filter_word = filter_word.strip()
130 # Don't filter if syntax was wrong
131 filter_column_value = u''
133 if search_expression is None:
134 search_expression = u'regex:title:^%s/' % pagename
136 search_result = search.searchPages(request, search_expression)
137 pages = [title.page_name for title in search_result.hits]
140 return _("**Could not find the referenced page: %s**") % search_expression
142 # ignore Template pages
143 filterfn = request.cfg.cache.page_template_regexact.search
144 templates = request.rootpage.getPageList(filter=filterfn)
145 subpages = [page for page in pages if page not in [templates, dictionary, pagename]]
147 return _("Subpage of '%(pagename)s' does not exist or you don't have enough rights.") % {"pagename": pagename}
150 # use selection and order
152 column_heading_keys = [key.strip() for key in column_heading.split(',')]
153 # use keys from template page
154 elif Page(request, template).exists():
155 page = Page(request, template)
156 page_dict = get_dict(request, template)
157 column_heading_keys = page_dict.keys()
159 # fallback use the keys of the first subpage
160 page = Page(request, subpages[0])
161 page_dict = get_dict(request, subpages[0])
162 column_heading_keys = page_dict.keys()
166 for key in column_heading_keys:
167 alias_dict[key] = key
168 if Page(request, dictionary).exists():
169 alias_dict = get_dict(request, dictionary)
170 heading_keys = [alias_dict[key] for key in column_heading_keys]
172 data = TupleDataset()
174 data.columns.extend([Column(pagename.strip('/'), label=pagename.strip('/'), align=align)])
175 # may be transpose should be moved into the databrowser widget
177 data.addRow([pagename.strip('/')] + heading_keys)
179 for name in subpages:
180 page = Page(request, name)
181 page_dict = get_dict(request, name)
182 if filter_column_value and page_dict.get(filter_key, '') != filter_word:
186 for key in column_heading_keys:
187 if key in page_dict.keys():
188 value = page_dict.get(key, '')
190 # xxx check how our brand new Image class solves this
191 if parser == u'text_moin_wiki':
192 value = value.replace('attachment:', 'attachment:%s/' % name)
193 row.append((wikiutil.renderText(request, WikiParser, value), wikiutil.escape(value, 1)))
195 row.append((wikiutil.escape(value, 1), wikiutil.escape(value, 1)))
199 parent, child = name.split('/', 1)
203 link = page.link_to(request, text="%s" % child)
204 data.addRow([link] + row)
206 data.columns.extend([Column(link, label=link, align=align)])
209 data.data = map(None, zip(*data.data))
210 data.data = data.data[1:]
212 # transpose does not support filter_selection
214 filtercols = filter_selection.split(',')
215 for key in column_heading_keys:
217 if filter_selection != u'NeverExistingDefaultFilter' and key in filtercols:
218 data.columns.append(Column(key, autofilter=(key in filtercols)))
220 data.columns.extend([Column(key, label=alias_dict[key], align=align)])
222 table = DataBrowserWidget(request)
225 names = sort_column_name.strip().split(',')
226 index = [column_heading_keys.index(name.strip()) + 1 for name in names]
230 rows = table2rows(data.data)
231 rows = sort_table(rows, cols=index, reverse=sort_reverse)
232 data.data = rows2table(rows)
234 html = ''.join(table.format(method='GET'))
235 # seems to work together with
236 # http://moinmo.in/FeatureRequests/SortableTables?action=AttachFile&do=view&target=common.js.patch
237 # html = html.replace('id="dbw.table', 'class="sortable" id="dbw.table')