0
|
1 #!/usr/bin/env python
|
|
2
|
|
3 import csv
|
|
4 import itertools
|
|
5 import string
|
|
6 import sys
|
|
7
|
|
8 input = sys.stdin
|
|
9 start_lines = input.readlines(10)
|
|
10 all_input = itertools.chain(iter(start_lines), input)
|
|
11
|
|
12 def detect_delimiter(iterable, char_set):
|
|
13 matches = (c for c in char_set if c in iterable)
|
|
14 return next(matches, None)
|
|
15
|
|
16 def detect_csv_dialect(sample):
|
|
17 try:
|
|
18 return csv.Sniffer().sniff(sample)
|
|
19 except:
|
|
20 return None
|
|
21
|
|
22 delimiter = detect_delimiter(start_lines[0], list('\t, '))
|
|
23 reader = None
|
|
24
|
|
25 if delimiter in list('\t,'):
|
|
26 # try to detect csv dialect, which should neatly handle quoted separators and stuff
|
|
27 dialect = detect_csv_dialect(''.join(start_lines))
|
|
28 if dialect:
|
|
29 reader = csv.reader(all_input, dialect)
|
|
30
|
|
31 if not reader:
|
|
32 if delimiter in list(string.whitespace):
|
|
33 # use str.split() with no arguments to split on arbitrary whitespace strings
|
|
34 reader = (line.strip().split() for line in all_input)
|
|
35 else:
|
|
36 reader = all_input
|
|
37
|
|
38 print """\
|
|
39 <!DOCTYPE html>
|
|
40 <html lang="en">
|
|
41 <head>
|
|
42 <meta http-equiv="content-type" content="text/html; charset=UTF-8"></meta>
|
|
43 <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.no-icons.min.css" rel="stylesheet">
|
|
44 <style>
|
|
45 div.dataTables_length label {
|
|
46 float: left;
|
|
47 text-align: left;
|
|
48 }
|
|
49
|
|
50 div.dataTables_length select {
|
|
51 width: 75px;
|
|
52 }
|
|
53
|
|
54 div.dataTables_filter label {
|
|
55 float: right;
|
|
56 }
|
|
57
|
|
58 div.dataTables_info {
|
|
59 padding-top: 8px;
|
|
60 }
|
|
61
|
|
62 div.dataTables_paginate {
|
|
63 float: right;
|
|
64 margin: 0;
|
|
65 }
|
|
66
|
|
67 table.table {
|
|
68 clear: both;
|
|
69 margin-bottom: 6px !important;
|
|
70 max-width: none !important;
|
|
71 }
|
|
72
|
|
73 table.table thead .sorting,
|
|
74 table.table thead .sorting_asc,
|
|
75 table.table thead .sorting_desc,
|
|
76 table.table thead .sorting_asc_disabled,
|
|
77 table.table thead .sorting_desc_disabled {
|
|
78 cursor: pointer;
|
|
79 *cursor: hand;
|
|
80 }
|
|
81
|
|
82
|
|
83 table.table thead .sorting { background: url('images/sort_both.png') no-repeat center right; }
|
|
84
|
|
85 //table.table thead .sorting_asc { background: url('images/sort_asc.png') no-repeat center right; }
|
|
86 //table.table thead .sorting_desc { background: url('images/sort_desc.png') no-repeat center right; }
|
|
87 table.table thead .sorting_asc { background: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_up.png') no-repeat center right; }
|
|
88 table.table thead .sorting_desc { background: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png') no-repeat center right; }
|
|
89
|
|
90 table.table thead .sorting_asc_disabled { background: url('images/sort_asc_disabled.png') no-repeat center right; }
|
|
91 table.table thead .sorting_desc_disabled { background: url('images/sort_desc_disabled.png') no-repeat center right; }
|
|
92
|
|
93 table.dataTable th:active {
|
|
94 outline: none;
|
|
95 }
|
|
96
|
|
97 /* Scrolling */
|
|
98 div.dataTables_scrollHead table {
|
|
99 margin-bottom: 0 !important;
|
|
100 border-bottom-left-radius: 0;
|
|
101 border-bottom-right-radius: 0;
|
|
102 }
|
|
103
|
|
104 div.dataTables_scrollHead table thead tr:last-child th:first-child,
|
|
105 div.dataTables_scrollHead table thead tr:last-child td:first-child {
|
|
106 border-bottom-left-radius: 0 !important;
|
|
107 border-bottom-right-radius: 0 !important;
|
|
108 }
|
|
109
|
|
110 div.dataTables_scrollBody table {
|
|
111 border-top: none;
|
|
112 margin-bottom: 0 !important;
|
|
113 }
|
|
114
|
|
115 div.dataTables_scrollBody tbody tr:first-child th,
|
|
116 div.dataTables_scrollBody tbody tr:first-child td {
|
|
117 border-top: none;
|
|
118 }
|
|
119
|
|
120 div.dataTables_scrollFoot table {
|
|
121 border-top: none;
|
|
122 }
|
|
123
|
|
124
|
|
125
|
|
126
|
|
127 /*
|
|
128 * TableTools styles
|
|
129 */
|
|
130 .table tbody tr.active td,
|
|
131 .table tbody tr.active th {
|
|
132 background-color: #08C;
|
|
133 color: white;
|
|
134 }
|
|
135
|
|
136 .table tbody tr.active:hover td,
|
|
137 .table tbody tr.active:hover th {
|
|
138 background-color: #0075b0 !important;
|
|
139 }
|
|
140
|
|
141 .table-striped tbody tr.active:nth-child(odd) td,
|
|
142 .table-striped tbody tr.active:nth-child(odd) th {
|
|
143 background-color: #017ebc;
|
|
144 }
|
|
145
|
|
146 table.DTTT_selectable tbody tr {
|
|
147 cursor: pointer;
|
|
148 *cursor: hand;
|
|
149 }
|
|
150
|
|
151 div.DTTT .btn {
|
|
152 color: #333 !important;
|
|
153 font-size: 12px;
|
|
154 }
|
|
155
|
|
156 div.DTTT .btn:hover {
|
|
157 text-decoration: none !important;
|
|
158 }
|
|
159
|
|
160
|
|
161 ul.DTTT_dropdown.dropdown-menu a {
|
|
162 color: #333 !important; /* needed only when demo_page.css is included */
|
|
163 }
|
|
164
|
|
165 ul.DTTT_dropdown.dropdown-menu li:hover a {
|
|
166 background-color: #0088cc;
|
|
167 color: white !important;
|
|
168 }
|
|
169
|
|
170 /* TableTools information display */
|
|
171 div.DTTT_print_info.modal {
|
|
172 height: 150px;
|
|
173 margin-top: -75px;
|
|
174 text-align: center;
|
|
175 }
|
|
176
|
|
177 div.DTTT_print_info h6 {
|
|
178 font-weight: normal;
|
|
179 font-size: 28px;
|
|
180 line-height: 28px;
|
|
181 margin: 1em;
|
|
182 }
|
|
183
|
|
184 div.DTTT_print_info p {
|
|
185 font-size: 14px;
|
|
186 line-height: 20px;
|
|
187 }
|
|
188
|
|
189
|
|
190
|
|
191 /*
|
|
192 * FixedColumns styles
|
|
193 */
|
|
194 div.DTFC_LeftHeadWrapper table,
|
|
195 div.DTFC_LeftFootWrapper table,
|
|
196 table.DTFC_Cloned tr.even {
|
|
197 background-color: white;
|
|
198 }
|
|
199
|
|
200 div.DTFC_LeftHeadWrapper table {
|
|
201 margin-bottom: 0 !important;
|
|
202 border-top-right-radius: 0 !important;
|
|
203 border-bottom-left-radius: 0 !important;
|
|
204 border-bottom-right-radius: 0 !important;
|
|
205 }
|
|
206
|
|
207 div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
|
|
208 div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
|
|
209 border-bottom-left-radius: 0 !important;
|
|
210 border-bottom-right-radius: 0 !important;
|
|
211 }
|
|
212
|
|
213 div.DTFC_LeftBodyWrapper table {
|
|
214 border-top: none;
|
|
215 margin-bottom: 0 !important;
|
|
216 }
|
|
217
|
|
218 div.DTFC_LeftBodyWrapper tbody tr:first-child th,
|
|
219 div.DTFC_LeftBodyWrapper tbody tr:first-child td {
|
|
220 border-top: none;
|
|
221 }
|
|
222
|
|
223 div.DTFC_LeftFootWrapper table {
|
|
224 border-top: none;
|
|
225 }
|
|
226 </style>
|
|
227 <script type="text/javascript" language="javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.0.min.js"></script>
|
|
228 <script type="text/javascript" language="javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
|
|
229 <script type="text/javascript" charset="utf-8">
|
|
230 /* Set the defaults for DataTables initialisation */
|
|
231 $.extend( true, $.fn.dataTable.defaults, {
|
|
232 "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>",
|
|
233 "sPaginationType": "bootstrap",
|
|
234 "oLanguage": {
|
|
235 "sLengthMenu": "_MENU_ records per page"
|
|
236 }
|
|
237 } );
|
|
238
|
|
239
|
|
240 /* Default class modification */
|
|
241 $.extend( $.fn.dataTableExt.oStdClasses, {
|
|
242 "sWrapper": "dataTables_wrapper form-inline"
|
|
243 } );
|
|
244
|
|
245
|
|
246 /* API method to get paging information */
|
|
247 $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
|
|
248 {
|
|
249 return {
|
|
250 "iStart": oSettings._iDisplayStart,
|
|
251 "iEnd": oSettings.fnDisplayEnd(),
|
|
252 "iLength": oSettings._iDisplayLength,
|
|
253 "iTotal": oSettings.fnRecordsTotal(),
|
|
254 "iFilteredTotal": oSettings.fnRecordsDisplay(),
|
|
255 "iPage": oSettings._iDisplayLength === -1 ?
|
|
256 0 : Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
|
|
257 "iTotalPages": oSettings._iDisplayLength === -1 ?
|
|
258 0 : Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
|
|
259 };
|
|
260 };
|
|
261
|
|
262
|
|
263 /* Bootstrap style pagination control */
|
|
264 $.extend( $.fn.dataTableExt.oPagination, {
|
|
265 "bootstrap": {
|
|
266 "fnInit": function( oSettings, nPaging, fnDraw ) {
|
|
267 var oLang = oSettings.oLanguage.oPaginate;
|
|
268 var fnClickHandler = function ( e ) {
|
|
269 e.preventDefault();
|
|
270 if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
|
|
271 fnDraw( oSettings );
|
|
272 }
|
|
273 };
|
|
274
|
|
275 $(nPaging).addClass('pagination').append(
|
|
276 '<ul>'+
|
|
277 '<li class="prev disabled"><a href="#">← '+oLang.sPrevious+'</a></li>'+
|
|
278 '<li class="next disabled"><a href="#">'+oLang.sNext+' → </a></li>'+
|
|
279 '</ul>'
|
|
280 );
|
|
281 var els = $('a', nPaging);
|
|
282 $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
|
|
283 $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
|
|
284 },
|
|
285
|
|
286 "fnUpdate": function ( oSettings, fnDraw ) {
|
|
287 var iListLength = 5;
|
|
288 var oPaging = oSettings.oInstance.fnPagingInfo();
|
|
289 var an = oSettings.aanFeatures.p;
|
|
290 var i, ien, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
|
|
291
|
|
292 if ( oPaging.iTotalPages < iListLength) {
|
|
293 iStart = 1;
|
|
294 iEnd = oPaging.iTotalPages;
|
|
295 }
|
|
296 else if ( oPaging.iPage <= iHalf ) {
|
|
297 iStart = 1;
|
|
298 iEnd = iListLength;
|
|
299 } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
|
|
300 iStart = oPaging.iTotalPages - iListLength + 1;
|
|
301 iEnd = oPaging.iTotalPages;
|
|
302 } else {
|
|
303 iStart = oPaging.iPage - iHalf + 1;
|
|
304 iEnd = iStart + iListLength - 1;
|
|
305 }
|
|
306
|
|
307 for ( i=0, ien=an.length ; i<ien ; i++ ) {
|
|
308 // Remove the middle elements
|
|
309 $('li:gt(0)', an[i]).filter(':not(:last)').remove();
|
|
310
|
|
311 // Add the new list items and their event handlers
|
|
312 for ( j=iStart ; j<=iEnd ; j++ ) {
|
|
313 sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
|
|
314 $('<li '+sClass+'><a href="#">'+j+'</a></li>')
|
|
315 .insertBefore( $('li:last', an[i])[0] )
|
|
316 .bind('click', function (e) {
|
|
317 e.preventDefault();
|
|
318 oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
|
|
319 fnDraw( oSettings );
|
|
320 } );
|
|
321 }
|
|
322
|
|
323 // Add / remove disabled classes from the static elements
|
|
324 if ( oPaging.iPage === 0 ) {
|
|
325 $('li:first', an[i]).addClass('disabled');
|
|
326 } else {
|
|
327 $('li:first', an[i]).removeClass('disabled');
|
|
328 }
|
|
329
|
|
330 if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
|
|
331 $('li:last', an[i]).addClass('disabled');
|
|
332 } else {
|
|
333 $('li:last', an[i]).removeClass('disabled');
|
|
334 }
|
|
335 }
|
|
336 }
|
|
337 }
|
|
338 } );
|
|
339
|
|
340
|
|
341 /*
|
|
342 * TableTools Bootstrap compatibility
|
|
343 * Required TableTools 2.1+
|
|
344 */
|
|
345 if ( $.fn.DataTable.TableTools ) {
|
|
346 // Set the classes that TableTools uses to something suitable for Bootstrap
|
|
347 $.extend( true, $.fn.DataTable.TableTools.classes, {
|
|
348 "container": "DTTT btn-group",
|
|
349 "buttons": {
|
|
350 "normal": "btn",
|
|
351 "disabled": "disabled"
|
|
352 },
|
|
353 "collection": {
|
|
354 "container": "DTTT_dropdown dropdown-menu",
|
|
355 "buttons": {
|
|
356 "normal": "",
|
|
357 "disabled": "disabled"
|
|
358 }
|
|
359 },
|
|
360 "print": {
|
|
361 "info": "DTTT_print_info modal"
|
|
362 },
|
|
363 "select": {
|
|
364 "row": "active"
|
|
365 }
|
|
366 } );
|
|
367
|
|
368 // Have the collection use a bootstrap compatible dropdown
|
|
369 $.extend( true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {
|
|
370 "collection": {
|
|
371 "container": "ul",
|
|
372 "button": "li",
|
|
373 "liner": "a"
|
|
374 }
|
|
375 } );
|
|
376 }
|
|
377
|
|
378
|
|
379 /* Table initialisation */
|
|
380 $(document).ready(function() {
|
|
381 $('#from_csv').dataTable( {
|
|
382 "sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>",
|
|
383 "sPaginationType": "bootstrap",
|
|
384 "oLanguage": {
|
|
385 "sLengthMenu": "_MENU_ records per page"
|
|
386 }
|
|
387 } );
|
|
388 } );
|
|
389 </script>
|
|
390 </head>
|
|
391 <body>
|
|
392 <div class="container" style="margin-top: 10px">
|
|
393 <table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered" id="from_csv">
|
|
394 <thead>\
|
|
395 """
|
|
396
|
|
397 for i, row in enumerate(reader):
|
|
398 if i == 0:
|
|
399 print "<tr><th>" + "</th><th>".join(row) + "</th></tr>"
|
|
400 else:
|
|
401 print "<tr><td>" + "</td><td>".join(row) + "</td></tr>"
|
|
402
|
|
403 if i == 0:
|
|
404 print "</thead><tbody>"
|
|
405
|
|
406 print """\
|
|
407 </tbody>
|
|
408 </table>
|
|
409 </div>
|
|
410 </body>
|
|
411 </html>\
|
|
412 """
|