This file is indexed.

/usr/share/pyshared/webhelpers/html/grid.py is in python-webhelpers 1.3-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
"""A helper to make an HTML table from a list of dicts, objects, or sequences.

A set of CSS styles complementing this helper is in
"webhelpers/html/public/stylesheets/grid.css". To use them, include the 
stylesheet in your applcation and set your <table> class to "stylized".

The documentation below is not very clear. This is a known bug. We need a
native English speaker who uses the module to volunteer to rewrite it.

This module is written and maintained by Ergo^.
"""

from webhelpers.html.builder import HTML, literal

class Grid(object):
    """
    This class is designed to aid programmer in the task of creation of
    tables/grids - structures that are mostly built from datasets.
    
    To create a grid at minimum one one needs to pass a dataset,
    like a list of dictionaries, or sqlalchemy proxy or query object::
    
        grid = Grid(itemlist, ['_numbered','c1', 'c2','c4'])

    where itemlist in this simple scenario is a list of dicts:

        [{'c1':1,'c2'...}, {'c1'...}, ...]
    
    This helper also received the list that defines order in which
    columns will be rendered - also keep note of special column name that can be
    passed in list that defines order - ``_numbered`` - this adds additional
    column that shows the number of item. For paging sql data there one can pass
    ``start_number`` argument to the grid to define where to start counting.
    Descendant sorting on ``_numbered`` column decrements the value, you can
    change how numberign function behaves by overloading ``calc_row_no`` 
    property.
    
    
    Converting the grid to a string renders the table rows. That's *just*
    the <tr> tags, not the <table> around them. The part outside the <tr>s
    have too many variations for us to render it. In many template systems,
    you can simply assign the grid to a template variable and it will be
    automatically converted to a string. Example using a Mako template:

    .. code-block:: html

        <table class="stylized">
        <caption>My Lovely Grid</caption>
        <col class="c1" />
        ${my_grid}
        </table>

    The names of the columns will get automatically converted for
    humans ie. foo_bar becomes Foo Bar. If you want the title to be something
    else you can change the grid.labels dict. If you want the column ``part_no``
    to become ``Catalogue Number`` just do::
    
        grid.labels[``part_no``] = u'Catalogue Number'
    
    It may be desired to exclude some or all columns from generation sorting
    urls (used by subclasses that are sorting aware). You can use grids
    exclude_ordering property to pass list of columns that should not support
    sorting. By default sorting is disabled - this ``exclude_ordering`` contains
    every column name.
        
    Since various programmers have different needs, Grid is highly customizable.
    By default grid attempts to read the value from dict directly by key.
    For every column it will try to output value of current_row['colname'].
    
    Since very often this behavior needs to be overridden like we need date
    formatted, use conditionals or generate a link one can use
    the  ``column_formats`` dict and pass a rendering function/lambda to it. 
    For example we want to apppend ``foo`` to part number::
    
        def custem_part_no_td(col_num, i, item):
            return HTML.td(`Foo %s` % item[``part_no``])
        
        grid.column_formats[``part_no``] = custem_part_no_td
    
    You can customize the grids look and behavior by overloading grids instance
    render functions::
    
        grid.default_column_format(self, column_number, i, record, column_name)
        by default generates markup like:
        <td class="cNO">VALUE</td>
        
        grid.default_header_column_format(self, column_number, column_name, 
            header_label)
        by default generates markup like:
        <td class="cNO COLUMN_NAME">VALUE</td>
            
        grid.default_header_ordered_column_format(self, column_number, order, 
            column_name, header_label)
        Used by grids that support ordering of columns in the grid like, 
        webhelpers.pylonslib.grid.GridPylons.
        by default generates markup like:
        <td class="cNO ordering ORDER_DIRECTION COLUMN_NAME">LABEL</td>
        
        grid.default_header_record_format(self, headers)
        by default generates markup like:
        <tr class="header">HEADERS_MARKUP</tr>
        
        grid.default_record_format(self, i, record, columns)
        Make an HTML table from a list of objects, and soon a list of
        sequences, a list of dicts, and a single dict. 
        <tr class="ODD_OR_EVEN">RECORD_MARKUP</tr>
        
        grid.generate_header_link(self, column_number, column, label_text)
        by default just sets the order direction and column properties for grid.
        Actual link generation is handled by sublasses of Grid.
        
        grid.numbered_column_format(self, column_number, i, record)
        by default generates markup like:
        <td class="cNO">RECORD_NO</td>
    """
    def __init__(self, itemlist, columns, column_labels=None,
                  column_formats=None, start_number=1,
                 order_column=None, order_direction=None, request=None,
                 url=None, **kw):
        """ additional keywords are appended to self.additional_kw 
        handy for url generation """
        self.labels = column_labels or {}
        self.exclude_ordering = columns
        self.itemlist = itemlist
        self.columns = columns
        self.column_formats = column_formats or {}
        if "_numbered" in columns:
            self.labels["_numbered"] = "#"
        if "_numbered" not in self.column_formats: 
            self.column_formats["_numbered"] = self.numbered_column_format 
        self.start_number = start_number
        self.order_dir = order_direction
        self.order_column = order_column
        #backward compatibility with old pylons grid
        if not hasattr(self,'request'):
            self.request = request
        self.url_generator = url
        self.additional_kw = kw
    
    def calc_row_no(self, i, column):
        if self.order_dir == 'dsc' and self.order_column == column:
            return self.start_number - i
        else:
            return self.start_number + i
        
    def make_headers(self):
        header_columns = []
            
        for i, column in enumerate(self.columns):
            # let"s generate header column contents
            label_text = ""
            if column in self.labels:
                label_text = self.labels[column]
            else:
                label_text = column.replace("_", " ").title()
            # handle non clickable columns
            if column in self.exclude_ordering:
                header = self.default_header_column_format(i + 1, column,
                    label_text)
            # handle clickable columns
            else:
                header = self.generate_header_link(i + 1, column, label_text)                
            header_columns.append(header)               
        return HTML(*header_columns)
    
    def make_columns(self, i, record):
        columns = []        
        for col_num, column in enumerate(self.columns):
            if column in self.column_formats:
                r = self.column_formats[column](col_num + 1,
                                                self. calc_row_no(i, column),
                                                record)
            else:
                r = self.default_column_format(col_num + 1,
                                               self.calc_row_no(i, column),
                                               record, column)
            columns.append(r)
        return HTML(*columns)
    
    def __html__(self):
        """ renders the grid """
        records = []
        #first render headers record
        headers = self.make_headers()
        r = self.default_header_record_format(headers)
        records.append(r)
        # now lets render the actual item grid
        for i, record in enumerate(self.itemlist):
            columns = self.make_columns(i, record)
            if hasattr(self, 'custom_record_format'):
                r = self.custom_record_format(i + 1, record, columns)
            else:
                r = self.default_record_format(i + 1, record, columns)
            records.append(r)
        return HTML(*records)
    
    def __str__(self):
        return self.__html__()

    def generate_header_link(self, column_number, column, label_text):
        """ This handles generation of link and then decides to call
        ``self.default_header_ordered_column_format`` 
        or 
        ``self.default_header_column_format`` 
        based on whether current column is the one that is used for sorting.
        
        you need to extend Grid class and overload this method implementing
        ordering here, whole operation consists of setting
        self.order_column and self.order_dir to their CURRENT values,
        and generating new urls for state that header should set set after its
        clicked
        
        (additional kw are passed to url gen. - like for webhelpers.paginate)
        example URL generation code below::
        
            GET = dict(self.request.copy().GET) # needs dict() for py2.5 compat
            self.order_column = GET.pop("order_col", None)
            self.order_dir = GET.pop("order_dir", None)       
            # determine new order
            if column == self.order_column and self.order_dir == "asc":
                new_order_dir = "dsc"
            else:
                new_order_dir = "asc"
            self.additional_kw['order_col'] = column
            self.additional_kw['order_dir'] = new_order_dir  
            # generate new url for example url_generator uses 
            # pylons's url.current() or pyramid's current_route_url()
            new_url = self.url_generator(**self.additional_kw)
            # set label for header with link
            label_text = HTML.tag("a", href=new_url, c=label_text)
        """ 
        
        # Is the current column the one we're ordering on?
        if (column == self.order_column):
            return self.default_header_ordered_column_format(column_number,
                                                             column,
                                                             label_text)
        else:
            return self.default_header_column_format(column_number, column,
                                                     label_text)            

    #### Default HTML tag formats ####

    def default_column_format(self, column_number, i, record, column_name):
        class_name = "c%s" % (column_number)
        return HTML.tag("td", record[column_name], class_=class_name)
    
    def numbered_column_format(self, column_number, i, record):
        class_name = "c%s" % (column_number)
        return HTML.tag("td", i, class_=class_name)

    def default_record_format(self, i, record, columns):
        if i % 2 == 0:
            class_name = "even r%s" % i
        else:
            class_name = "odd r%s" % i
        return HTML.tag("tr", columns, class_=class_name)

    def default_header_record_format(self, headers):
        return HTML.tag("tr", headers, class_="header")

    def default_header_ordered_column_format(self, column_number, column_name,
                                             header_label):
        header_label = HTML(header_label, HTML.tag("span", class_="marker"))
        if column_name == "_numbered":
            column_name = "numbered"
        class_name = "c%s ordering %s %s" % (column_number, self.order_dir, column_name)
        return HTML.tag("td", header_label, class_=class_name)

    def default_header_column_format(self, column_number, column_name,
        header_label):
        if column_name == "_numbered":
            column_name = "numbered"
        if column_name in self.exclude_ordering:
            class_name = "c%s %s" % (column_number, column_name)
            return HTML.tag("td", header_label, class_=class_name)
        else:
            header_label = HTML(header_label, HTML.tag("span", class_="marker"))
            class_name = "c%s ordering %s" % (column_number, column_name)
            return HTML.tag("td", header_label, class_=class_name)


class ObjectGrid(Grid):
    """ A grid class for a sequence of objects.
    
    This grid class assumes that the rows are objects rather than dicts, and
    uses attribute access to retrieve the column values. It works well with
    SQLAlchemy ORM instances.
    """
    def default_column_format(self, column_number, i, record, column_name):
        class_name = "c%s" % (column_number)
        return HTML.tag("td", getattr(record, column_name), class_=class_name)

class ListGrid(Grid):
    """ A grid class for a sequence of lists.
    
    This grid class assumes that the rows are lists rather than dicts, and
    uses subscript access to retrieve the column values. Some constructor args
    are also different.

    If ``columns`` is not specified in the constructor, it will examine 
    ``itemlist[0]`` to determine the number of columns, and display them in
    order.  This works only if ``itemlist`` is a sequence and not just an
    iterable.  Alternatively, you can pass an int to specify the number of
    columns, or a list of int subscripts to override the column order.
    Examples::
    
        grid = ListGrid(list_data)
        grid = ListGrid(list_data, columns=4)
        grid = ListGrid(list_data, columns=[1, 3, 2, 0]) 

    ``column_labels`` may be a list of strings. The class will calculate the
    appropriate subscripts for the superclass dict.
    
    """
    def __init__(self, itemlist, columns=None, column_labels=None, *args, **kw):
        if columns is None:
            columns = range(len(itemlist[0]))
        elif isinstance(columns, int):
            columns = range(columns)
        # The superclass requires the ``columns`` elements to be strings.
        super_columns = [str(x) for x in columns]
        # The superclass requires ``column_labels`` to be a dict.
        super_labels = column_labels
        if isinstance(column_labels, (list, tuple)):
            super_labels = dict(zip(super_columns, column_labels))
        Grid.__init__(self, itemlist, super_columns, super_labels, *args, **kw)
  
    def default_column_format(self, column_number, i, record, column_name):
        class_name = "c%s" % (column_number)
        return HTML.tag("td", record[int(column_name)], class_=class_name)