1.1 --- a/ImprovedTableParser.py Sun Feb 19 00:54:13 2012 +0100
1.2 +++ b/ImprovedTableParser.py Sun Feb 19 13:38:53 2012 +0100
1.3 @@ -280,32 +280,44 @@
1.4 ascending = False
1.5
1.6 # Extract the conversion indicator and column index.
1.7 -
1.8 - if column_spec.endswith("n"):
1.9 - column = column_spec[:-1]
1.10 - fn = to_number
1.11 - else:
1.12 - column = column_spec
1.13 - fn = str
1.14 -
1.15 # Ignore badly-specified columns.
1.16
1.17 try:
1.18 + column = get_number(column_spec)
1.19 + suffix = column_spec[len(column):]
1.20 + fn = converters[suffix]
1.21 sort_columns.append((max(0, int(column) - start), fn, ascending))
1.22 except ValueError:
1.23 pass
1.24
1.25 return sort_columns
1.26
1.27 +def get_column_types(sort_columns):
1.28 +
1.29 + """
1.30 + Return a dictionary mapping column indexes to conversion functions.
1.31 + """
1.32 +
1.33 + d = {}
1.34 + for column, fn, ascending in sort_columns:
1.35 + d[column] = fn, ascending
1.36 + return d
1.37 +
1.38 +def get_number(s):
1.39 +
1.40 + "From 's', get any leading number."
1.41 +
1.42 + match = leading_number_regexp.match(s)
1.43 + if match:
1.44 + return match.group()
1.45 + else:
1.46 + return ""
1.47 +
1.48 def to_number(s):
1.49
1.50 "Convert 's' to a number, discarding any non-numeric trailing data."
1.51
1.52 - match = leading_number_regexp.match(s)
1.53 - if match:
1.54 - return int(match.group())
1.55 - else:
1.56 - raise ValueError, s
1.57 + return int(get_number(s))
1.58
1.59 class Sorter:
1.60
1.61 @@ -342,6 +354,80 @@
1.62
1.63 return 0
1.64
1.65 +def write_sort_control(columnnumber, write, sort_columns, column_types, columns, table_name, data_start, start=0):
1.66 +
1.67 + """
1.68 + Write a sort control in its own form which provides a list of sort
1.69 + descriptions, modifying the 'sort_columns' provided by introducing the given
1.70 + column in different positions.
1.71 + """
1.72 +
1.73 + option_html = """\
1.74 + <option value="%(value)s" %(selected)s>%(label)s</option>
1.75 +"""
1.76 +
1.77 + # Start with the existing criteria without this column being involved.
1.78 +
1.79 + current_sort_columns = [(column + start, suffixes[fn], not ascending and "d" or "")
1.80 + for (column, fn, ascending) in sort_columns]
1.81 + revised_sort_columns = [(column + start, suffixes[fn], not ascending and "d" or "")
1.82 + for (column, fn, ascending) in sort_columns if column != columnnumber]
1.83 + values = [revised_sort_columns]
1.84 + revised_sort_labels = [columns[column][1].strip() for (column, fn, ascending) in revised_sort_columns]
1.85 + labels = [revised_sort_labels]
1.86 +
1.87 + # Add this column in all possible places in the sorting criteria.
1.88 +
1.89 + i = 0
1.90 + while i <= len(revised_sort_columns):
1.91 + value = revised_sort_columns[:]
1.92 + label = revised_sort_labels[:]
1.93 + fn, ascending = column_types.get(columnnumber, (str, True))
1.94 + value.insert(i, (columnnumber + start, suffixes[fn], not ascending and "d" or ""))
1.95 + label.insert(i, columns[columnnumber][1].strip())
1.96 + values.append(value)
1.97 + labels.append(label)
1.98 + i += 1
1.99 +
1.100 + # Make the list of options.
1.101 +
1.102 + options_html = []
1.103 + for value, label in zip(values, labels):
1.104 + options_html.append(option_html % {
1.105 + "value" : ",".join([("%d%s%s" % spec) for spec in value]),
1.106 + "label" : ", ".join(label),
1.107 + "selected" : value == current_sort_columns and 'selected="selected"' or "",
1.108 + })
1.109 +
1.110 + # Write the form.
1.111 +
1.112 + d = {
1.113 + "table_name" : table_name,
1.114 + "options" : "".join(options_html),
1.115 + "data_start" : data_start,
1.116 + }
1.117 +
1.118 + write("""\
1.119 +<form method="post">
1.120 + <input name="tablename" value="%(table_name)s" type="hidden" />
1.121 + <input name="%(table_name)s-headers" value="%(data_start)s" type="hidden" />
1.122 + <select name="%(table_name)s-sortcolumns" onchange="this.form.submit()">
1.123 +%(options)s
1.124 + </select>
1.125 +</form>
1.126 +""" % d)
1.127 +
1.128 +# Sorting-related tables.
1.129 +
1.130 +converters = {
1.131 + "n" : to_number,
1.132 + "" : str,
1.133 + }
1.134 +
1.135 +suffixes = {}
1.136 +for key, value in converters.items():
1.137 + suffixes[value] = key
1.138 +
1.139 # Common formatting functions.
1.140
1.141 def formatTable(text, request, fmt, attrs=None):
1.142 @@ -358,36 +444,53 @@
1.143 # Override any region arguments with request parameters.
1.144
1.145 table_name = attrs.get("name")
1.146 - sortcolumns = table_name and getQualifiedParameter(request, table_name, "sortcolumns") or attrs.get("sortcolumns")
1.147 +
1.148 + # Get sorting criteria from the region and the request.
1.149 +
1.150 + region_sortcolumns = attrs.get("sortcolumns")
1.151 + sortcolumns = table_name and getQualifiedParameter(request, table_name, "sortcolumns") or region_sortcolumns
1.152
1.153 # Sort the rows according to the values in each of the specified columns.
1.154
1.155 + data_start = int(table_name and getQualifiedParameter(request, table_name, "headers") or attrs.get("headers", "1"))
1.156 +
1.157 if sortcolumns:
1.158 - data_start = int(attrs.get("headers", "1"))
1.159 headers = table[:data_start]
1.160 data = table[data_start:]
1.161
1.162 # Get the sort columns using Unix sort-like notation.
1.163
1.164 - sorter = Sorter(get_sort_columns(sortcolumns))
1.165 + sort_columns = get_sort_columns(sortcolumns)
1.166 + region_sort_columns = get_sort_columns(region_sortcolumns)
1.167 +
1.168 + sorter = Sorter(sort_columns)
1.169 data.sort(cmp=sorter)
1.170
1.171 table = headers + data
1.172 + column_types = get_column_types(region_sort_columns)
1.173
1.174 # Write the table.
1.175
1.176 - request.write(fmt.table(1, table_attrs))
1.177 + writing_html = request.page.output_mimetype == "text/html"
1.178 + write = request.write
1.179 + write(fmt.table(1, table_attrs))
1.180
1.181 - for row_attrs, columns in table:
1.182 - request.write(fmt.table_row(1, row_attrs))
1.183 + for rownumber, (row_attrs, columns) in enumerate(table):
1.184 + write(fmt.table_row(1, row_attrs))
1.185 +
1.186 + for columnnumber, (column_attrs, column_text) in enumerate(columns):
1.187 + write(fmt.table_cell(1, column_attrs))
1.188 + write(formatText(column_text, request, fmt))
1.189
1.190 - for column_attrs, column_text in columns:
1.191 - request.write(fmt.table_cell(1, column_attrs))
1.192 - request.write(formatText(column_text, request, fmt))
1.193 - request.write(fmt.table_cell(0))
1.194 + # Add sorting controls, if appropriate.
1.195 +
1.196 + if writing_html and sortcolumns and rownumber == data_start - 1:
1.197 + write_sort_control(columnnumber, write, sort_columns, column_types, columns, table_name, data_start)
1.198
1.199 - request.write(fmt.table_row(0))
1.200 + write(fmt.table_cell(0))
1.201
1.202 - request.write(fmt.table(0))
1.203 + write(fmt.table_row(0))
1.204 +
1.205 + write(fmt.table(0))
1.206
1.207 # vim: tabstop=4 expandtab shiftwidth=4