table_setter 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +20 -0
- data/LICENSE +20 -0
- data/README +10 -0
- data/Rakefile +66 -0
- data/TODO +3 -0
- data/VERSION.yml +5 -0
- data/bin/table-setter +5 -0
- data/doc/TableFu/Formatting.html +178 -0
- data/doc/TableSetter/App.html +176 -0
- data/doc/TableSetter/Command.html +376 -0
- data/doc/TableSetter/Table.html +1813 -0
- data/doc/TableSetter.html +292 -0
- data/doc/_index.html +146 -0
- data/doc/class_list.html +36 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +50 -0
- data/doc/css/style.css +268 -0
- data/doc/file.README.html +68 -0
- data/doc/file_list.html +38 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +68 -0
- data/doc/js/app.js +99 -0
- data/doc/js/full_list.js +106 -0
- data/doc/js/jquery.js +19 -0
- data/doc/method_list.html +291 -0
- data/doc/top-level-namespace.html +85 -0
- data/documentation/css/dawn.css +121 -0
- data/documentation/css/styles.css +63 -0
- data/documentation/images/folder.png +0 -0
- data/documentation/images/key.png +0 -0
- data/documentation/images/proplogo.png +0 -0
- data/documentation/images/publish.png +0 -0
- data/documentation/images/text-x-generic.png +0 -0
- data/documentation/index.html.erb +221 -0
- data/documentation/tables/example/index.html +4074 -0
- data/documentation/tables/example_faceted/index.html +17239 -0
- data/documentation/tables/example_formatted/index.html +861 -0
- data/documentation/tables/example_local/1/index.html +6084 -0
- data/documentation/tables/example_local/10/index.html +6084 -0
- data/documentation/tables/example_local/11/index.html +6084 -0
- data/documentation/tables/example_local/12/index.html +6084 -0
- data/documentation/tables/example_local/13/index.html +6084 -0
- data/documentation/tables/example_local/14/index.html +6084 -0
- data/documentation/tables/example_local/15/index.html +6084 -0
- data/documentation/tables/example_local/16/index.html +6084 -0
- data/documentation/tables/example_local/17/index.html +6084 -0
- data/documentation/tables/example_local/18/index.html +6084 -0
- data/documentation/tables/example_local/19/index.html +6084 -0
- data/documentation/tables/example_local/2/index.html +6084 -0
- data/documentation/tables/example_local/20/index.html +6084 -0
- data/documentation/tables/example_local/21/index.html +6084 -0
- data/documentation/tables/example_local/22/index.html +6084 -0
- data/documentation/tables/example_local/23/index.html +6084 -0
- data/documentation/tables/example_local/24/index.html +1404 -0
- data/documentation/tables/example_local/3/index.html +6084 -0
- data/documentation/tables/example_local/4/index.html +6084 -0
- data/documentation/tables/example_local/5/index.html +6084 -0
- data/documentation/tables/example_local/6/index.html +6084 -0
- data/documentation/tables/example_local/7/index.html +6084 -0
- data/documentation/tables/example_local/8/index.html +6084 -0
- data/documentation/tables/example_local/9/index.html +6084 -0
- data/documentation/tables/example_local/index.html +6084 -0
- data/documentation/tables/favicon.ico +0 -0
- data/documentation/tables/images/th_arrow_asc.gif +0 -0
- data/documentation/tables/images/th_arrow_desc.gif +0 -0
- data/documentation/tables/index.html +48 -0
- data/documentation/tables/javascripts/application.js +32 -0
- data/documentation/tables/javascripts/jquery.tablesorter.js +852 -0
- data/documentation/tables/javascripts/jquery.tablesorter.multipagefilter.js +111 -0
- data/documentation/tables/javascripts/jquery.tablesorter.pager.js +183 -0
- data/documentation/tables/stylesheets/stylesheet.css +67 -0
- data/index.html +238 -0
- data/lib/table_setter/app.rb +54 -0
- data/lib/table_setter/command.rb +139 -0
- data/lib/table_setter/table.rb +226 -0
- data/lib/table_setter.rb +32 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/table-setter-app_spec.rb +24 -0
- data/spec/table-setter_spec.rb +179 -0
- data/table_setter.gemspec +171 -0
- data/template/config.ru +33 -0
- data/template/public/favicon.ico +0 -0
- data/template/public/images/th_arrow_asc.gif +0 -0
- data/template/public/images/th_arrow_desc.gif +0 -0
- data/template/public/javascripts/application.js +32 -0
- data/template/public/javascripts/jquery.tablesorter.js +852 -0
- data/template/public/javascripts/jquery.tablesorter.multipagefilter.js +111 -0
- data/template/public/javascripts/jquery.tablesorter.pager.js +183 -0
- data/template/public/stylesheets/stylesheet.css +74 -0
- data/template/tables/example.yml +21 -0
- data/template/tables/example_faceted.yml +27 -0
- data/template/tables/example_formatted.csv +1 -0
- data/template/tables/example_formatted.yml +27 -0
- data/template/tables/example_local.csv +5806 -0
- data/template/tables/example_local.yml +27 -0
- data/template/views/404.erb +4 -0
- data/template/views/500.erb +4 -0
- data/template/views/index.erb +7 -0
- data/template/views/layout.erb +34 -0
- data/template/views/table.erb +78 -0
- metadata +240 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
(function($){
|
2
|
+
$.extend({
|
3
|
+
tablesorterMultiPageFilter : new function(){
|
4
|
+
|
5
|
+
function replaceRows(table){
|
6
|
+
// clear the table body
|
7
|
+
$.tablesorter.clearTableBody(table);
|
8
|
+
var tableBody = $(table.tBodies[0]);
|
9
|
+
|
10
|
+
for(var i = 0; i < table.config.collection.length; i++) {
|
11
|
+
var o = table.config.collection[i];
|
12
|
+
var l = o.length;
|
13
|
+
for(var j=0; j < l; j++) {
|
14
|
+
tableBody[0].appendChild(o[j]);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
$(table).trigger("applyWidgets");
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
function renderTable(table){
|
22
|
+
var newString = table.config.filterSelector[0].value;
|
23
|
+
if(newString.length > 1){
|
24
|
+
if(table.config.container){
|
25
|
+
table.config.container.hide();
|
26
|
+
}
|
27
|
+
|
28
|
+
var toShow = [];
|
29
|
+
newString = $.trim(newString);
|
30
|
+
var words = newString.toLowerCase().split(" ");
|
31
|
+
|
32
|
+
// no change, don't do anything
|
33
|
+
if (newString === table.config.string) return false;
|
34
|
+
// press was just a string
|
35
|
+
if (newString[-1] === " ") { table.config.string = newString; return false; }
|
36
|
+
// most of the string is old
|
37
|
+
if (newString.indexOf(table.config.string) > -1){
|
38
|
+
// don't change the search array but we only need the last word
|
39
|
+
words = [words.pop()];
|
40
|
+
} else {
|
41
|
+
// we need to search all rows
|
42
|
+
table.config.collection = table.config.rowsCopy.slice(0);
|
43
|
+
};
|
44
|
+
|
45
|
+
// split out words
|
46
|
+
len = table.config.collection.length;
|
47
|
+
var counter = 0;
|
48
|
+
for(var j = 0; j < len; j++ ){
|
49
|
+
var text = table.config.collection[j].text().toLowerCase();
|
50
|
+
for (var i=0; i < words.length; i++) {
|
51
|
+
if (text.indexOf(words[i]) > -1) {
|
52
|
+
toShow.push(table.config.collection[j]);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
counter++;
|
56
|
+
};
|
57
|
+
table.config.collection = toShow.slice(0);
|
58
|
+
replaceRows(table);
|
59
|
+
table.config.string = newString;
|
60
|
+
} else {
|
61
|
+
table.config.string = "";
|
62
|
+
table.config.collection = table.config.rowsCopy.slice(0);
|
63
|
+
if(table.config.container){
|
64
|
+
table.config.container.show();
|
65
|
+
} else {
|
66
|
+
replaceRows(table);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
this.defaults = {
|
72
|
+
filterSelector: $("#filter")
|
73
|
+
}
|
74
|
+
|
75
|
+
this.init = function(settings) {
|
76
|
+
return this.each(function(){
|
77
|
+
config = $.extend(this.config, $.tablesorterMultiPageFilter.defaults, settings);
|
78
|
+
|
79
|
+
var table = this,
|
80
|
+
filter = config.filterSelector
|
81
|
+
;
|
82
|
+
|
83
|
+
// save old appenders and define a new one that grabs the row cache and saves it
|
84
|
+
if(!table.config.rowsCopy){
|
85
|
+
var oldAppend = config.appender || function (table, rows) {};
|
86
|
+
this.config.appender = function(table, rows){
|
87
|
+
table.config.rowsCopy = rows;
|
88
|
+
oldAppend(table, rows);
|
89
|
+
}
|
90
|
+
$(this).trigger("appendCache");
|
91
|
+
}
|
92
|
+
table.config.string = "";
|
93
|
+
table.config.collection = [];
|
94
|
+
table.config.collection = table.config.rowsCopy.slice(0)
|
95
|
+
|
96
|
+
function filterMe(){
|
97
|
+
renderTable(table);
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
$(filter).keyup(filterMe);
|
101
|
+
$(filter).submit(filterMe);
|
102
|
+
});
|
103
|
+
}
|
104
|
+
}
|
105
|
+
});
|
106
|
+
|
107
|
+
|
108
|
+
$.fn.extend({
|
109
|
+
tablesorterMultiPageFilter: $.tablesorterMultiPageFilter.init
|
110
|
+
});
|
111
|
+
}(jQuery))
|
@@ -0,0 +1,183 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.extend({
|
3
|
+
tablesorterPager: new function() {
|
4
|
+
|
5
|
+
function updatePageDisplay(c) {
|
6
|
+
var s = $(c.cssPageDisplay,c.container).text((c.page+1) + c.seperator + c.totalPages);
|
7
|
+
}
|
8
|
+
|
9
|
+
function setPageSize(table,size) {
|
10
|
+
var c = table.config;
|
11
|
+
c.size = size;
|
12
|
+
c.totalPages = Math.ceil(c.totalRows / c.size);
|
13
|
+
c.pagerPositionSet = false;
|
14
|
+
moveToPage(table);
|
15
|
+
fixPosition(table);
|
16
|
+
}
|
17
|
+
|
18
|
+
function fixPosition(table) {
|
19
|
+
var c = table.config;
|
20
|
+
if(!c.pagerPositionSet && c.positionFixed) {
|
21
|
+
var c = table.config, o = $(table);
|
22
|
+
if(o.offset) {
|
23
|
+
c.container.css({
|
24
|
+
top: o.offset().top + o.height() + 'px',
|
25
|
+
position: 'absolute'
|
26
|
+
});
|
27
|
+
}
|
28
|
+
c.pagerPositionSet = true;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
function moveToFirstPage(table) {
|
33
|
+
var c = table.config;
|
34
|
+
c.page = 0;
|
35
|
+
moveToPage(table);
|
36
|
+
}
|
37
|
+
|
38
|
+
function moveToLastPage(table) {
|
39
|
+
var c = table.config;
|
40
|
+
c.page = (c.totalPages-1);
|
41
|
+
moveToPage(table);
|
42
|
+
}
|
43
|
+
|
44
|
+
function moveToNextPage(table) {
|
45
|
+
var c = table.config;
|
46
|
+
c.page++;
|
47
|
+
if(c.page >= (c.totalPages-1)) {
|
48
|
+
c.page = (c.totalPages-1);
|
49
|
+
}
|
50
|
+
moveToPage(table);
|
51
|
+
}
|
52
|
+
|
53
|
+
function moveToPrevPage(table) {
|
54
|
+
var c = table.config;
|
55
|
+
c.page--;
|
56
|
+
if(c.page <= 0) {
|
57
|
+
c.page = 0;
|
58
|
+
}
|
59
|
+
moveToPage(table);
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
function moveToPage(table) {
|
64
|
+
var c = table.config;
|
65
|
+
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
66
|
+
c.page = 0;
|
67
|
+
}
|
68
|
+
|
69
|
+
renderTable(table,c.rowsCopy);
|
70
|
+
}
|
71
|
+
|
72
|
+
function renderTable(table,rows) {
|
73
|
+
|
74
|
+
var c = table.config;
|
75
|
+
var l = rows.length;
|
76
|
+
var s = (c.page * c.size);
|
77
|
+
var e = (s + c.size);
|
78
|
+
if(e > rows.length ) {
|
79
|
+
e = rows.length;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
var tableBody = $(table.tBodies[0]);
|
84
|
+
|
85
|
+
// clear the table body
|
86
|
+
|
87
|
+
$.tablesorter.clearTableBody(table);
|
88
|
+
|
89
|
+
for(var i = s; i < e; i++) {
|
90
|
+
|
91
|
+
//tableBody.append(rows[i]);
|
92
|
+
|
93
|
+
var o = rows[i];
|
94
|
+
var l = o.length;
|
95
|
+
for(var j=0; j < l; j++) {
|
96
|
+
|
97
|
+
tableBody[0].appendChild(o[j]);
|
98
|
+
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
fixPosition(table,tableBody);
|
103
|
+
|
104
|
+
$(table).trigger("applyWidgets");
|
105
|
+
|
106
|
+
if( c.page >= c.totalPages ) {
|
107
|
+
moveToLastPage(table);
|
108
|
+
}
|
109
|
+
|
110
|
+
updatePageDisplay(c);
|
111
|
+
}
|
112
|
+
|
113
|
+
this.appender = function(table,rows) {
|
114
|
+
|
115
|
+
var c = table.config;
|
116
|
+
|
117
|
+
c.rowsCopy = rows;
|
118
|
+
c.totalRows = rows.length;
|
119
|
+
c.totalPages = Math.ceil(c.totalRows / c.size);
|
120
|
+
renderTable(table,rows);
|
121
|
+
};
|
122
|
+
|
123
|
+
this.defaults = {
|
124
|
+
size: 10,
|
125
|
+
offset: 0,
|
126
|
+
page: 0,
|
127
|
+
totalRows: 0,
|
128
|
+
totalPages: 0,
|
129
|
+
container: null,
|
130
|
+
cssNext: '.next',
|
131
|
+
cssPrev: '.prev',
|
132
|
+
cssFirst: '.first',
|
133
|
+
cssLast: '.last',
|
134
|
+
cssPageDisplay: '.pagedisplay',
|
135
|
+
cssPageSize: '.pagesize',
|
136
|
+
seperator: "/",
|
137
|
+
positionFixed: true,
|
138
|
+
appender: this.appender
|
139
|
+
};
|
140
|
+
|
141
|
+
this.construct = function(settings) {
|
142
|
+
|
143
|
+
return this.each(function() {
|
144
|
+
|
145
|
+
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
146
|
+
|
147
|
+
var table = this, pager = config.container;
|
148
|
+
|
149
|
+
$(this).trigger("appendCache");
|
150
|
+
|
151
|
+
config.size = parseInt($(".pagesize",pager).val());
|
152
|
+
|
153
|
+
$(config.cssFirst,pager).click(function() {
|
154
|
+
moveToFirstPage(table);
|
155
|
+
return false;
|
156
|
+
});
|
157
|
+
$(config.cssNext,pager).click(function() {
|
158
|
+
moveToNextPage(table);
|
159
|
+
return false;
|
160
|
+
});
|
161
|
+
$(config.cssPrev,pager).click(function() {
|
162
|
+
moveToPrevPage(table);
|
163
|
+
return false;
|
164
|
+
});
|
165
|
+
$(config.cssLast,pager).click(function() {
|
166
|
+
moveToLastPage(table);
|
167
|
+
return false;
|
168
|
+
});
|
169
|
+
$(config.cssPageSize,pager).change(function() {
|
170
|
+
setPageSize(table,parseInt($(this).val()));
|
171
|
+
return false;
|
172
|
+
});
|
173
|
+
});
|
174
|
+
};
|
175
|
+
|
176
|
+
}
|
177
|
+
});
|
178
|
+
// extend plugin scope
|
179
|
+
$.fn.extend({
|
180
|
+
tablesorterPager: $.tablesorterPager.construct
|
181
|
+
});
|
182
|
+
|
183
|
+
})(jQuery);
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#table_fu{
|
2
|
+
width: 980px;
|
3
|
+
margin-left: auto;
|
4
|
+
margin-right: auto;
|
5
|
+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
6
|
+
font-size: 14px;
|
7
|
+
line-height: 20px;
|
8
|
+
color: #333;
|
9
|
+
}
|
10
|
+
#table_fu *{
|
11
|
+
margin: 0;
|
12
|
+
padding: 0;
|
13
|
+
}
|
14
|
+
#table_fu div#table_title{
|
15
|
+
font-size: 24px;
|
16
|
+
font-weight: bold;
|
17
|
+
font-family: Palatino Linotype,Book Antiqua,Palatino,serif;
|
18
|
+
}
|
19
|
+
#table_fu div{
|
20
|
+
margin-bottom: 14px;
|
21
|
+
}
|
22
|
+
#table_fu div#pager{
|
23
|
+
float:right;
|
24
|
+
width: 15%;
|
25
|
+
}
|
26
|
+
#table_fu div#pager div.pagedisplay{
|
27
|
+
display: inline;
|
28
|
+
}
|
29
|
+
#table_fu div#filter{
|
30
|
+
float:left;
|
31
|
+
width:30%;
|
32
|
+
}
|
33
|
+
|
34
|
+
#table_fu #data{
|
35
|
+
border: 1px solid #ababab;
|
36
|
+
border-collapse: collapse;
|
37
|
+
margin-bottom:14px;
|
38
|
+
width: 100%;
|
39
|
+
}
|
40
|
+
#table_fu td, #table_fu th{
|
41
|
+
padding: 7px;
|
42
|
+
border-bottom: 1px solid #ababab;
|
43
|
+
text-align: center;
|
44
|
+
}
|
45
|
+
#table_fu th{
|
46
|
+
cursor: pointer;
|
47
|
+
vertical-align: bottom;
|
48
|
+
}
|
49
|
+
#table_fu td.sorted{
|
50
|
+
background-color: #edf4ff;
|
51
|
+
}
|
52
|
+
#table_fu td .bar{
|
53
|
+
width: 100%;
|
54
|
+
height: 100%;
|
55
|
+
text-align:left;
|
56
|
+
background-color: #99CA3C;
|
57
|
+
color:#444;
|
58
|
+
padding:0.5em;
|
59
|
+
margin-top: 0.7em;
|
60
|
+
font-weight:bold;
|
61
|
+
}
|
62
|
+
#table_fu th.headerSortDown{
|
63
|
+
background: #ccc url(../images/th_arrow_asc.gif) no-repeat 100% 75%;
|
64
|
+
}
|
65
|
+
#table_fu th.headerSortUp{
|
66
|
+
background: #ccc url(../images/th_arrow_desc.gif) no-repeat 100% 75%;
|
67
|
+
}
|
data/index.html
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
5
|
+
<title>TableSetter</title>
|
6
|
+
<link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
|
7
|
+
<link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<a href="http://www.propublica.org" class="propublica"> </a>
|
11
|
+
<h1>TableSetter <small>– Version: 0.1.2</small></h1>
|
12
|
+
<p><a href="https://github.com/propublica/table-setter">TableSetter</a> is a Ruby app that provides an easy way to present CSVs hosted locally or remotely (e.g. on google, etc) in custom HTML. TableSetter in the wild: <a href="http://projects.propublica.org/tables/failed-banks">a list of all stimulus projects from last year</a>, <a href="http://projects.propublica.org/tables/stimulus-spending-progress">the stimulus spending progress</a>, or <a href="http://projects.propublica.org/tables/failed-banks">a list of failed banks due to the last recession</a>.</p>
|
13
|
+
<p>Each table is filterable and sortable on multiple columns. Also each column can be formatted in one of many different styles. In production mode, <strong>TableSetter</strong> provides valid expires headers and can be coupled with an upstream cache like <a href="http://rtomayko.github.com/rack-cache/">Rack::Cache</a> or varnish for speedy presentation.</p>
|
14
|
+
<h2><a id="toc">Table of Contents</a></h2>
|
15
|
+
<ul>
|
16
|
+
<li><a href="#installation">Installation</a></li>
|
17
|
+
<li><a href="#tablesetter">The table-setter command</a></li>
|
18
|
+
<li><a href="#thedirectory">The Configuration Directory</a></li>
|
19
|
+
<li><a href="#thefile">A TableSetter File</a></li>
|
20
|
+
<li><a href="#deployment">Deployment</a></li>
|
21
|
+
<li><a href="#rails">Rails</a></li>
|
22
|
+
<li><a href="#links">Links</a></li>
|
23
|
+
<li><a href="#credits">Credits</a></li>
|
24
|
+
<li><a href="#license">License</a></li>
|
25
|
+
</ul>
|
26
|
+
<h2><a id="installation" href="#toc">Installation</a></h2>
|
27
|
+
<p>Install <strong>TableSetter</strong> through rubygems:</p>
|
28
|
+
<pre class="dawn">
|
29
|
+
gem install table_setter</pre>
|
30
|
+
<p>or from the source files:</p>
|
31
|
+
<pre class="dawn">
|
32
|
+
git clone git://github.com/propublica/table-setter.git
|
33
|
+
cd table-setter
|
34
|
+
rake install</pre>
|
35
|
+
<p>After you've installed the gem you'll have a new executable: <strong>table-setter</strong>. You can view the subcommands available by typing <strong>table-setter --help</strong>. To set things up you'll need to run it with the <strong>install</strong> command to install the configuration files and ERB templates into a directory. </p>
|
36
|
+
<pre>
|
37
|
+
table-setter install path/to/directory</pre>
|
38
|
+
<p>
|
39
|
+
To start the development server run:
|
40
|
+
</p>
|
41
|
+
<pre>
|
42
|
+
table-setter start path/to/directory</pre>
|
43
|
+
<p>Go to development url, <a href="http://localhost:3000/">http://localhost:3000/</a> and you'll see a list of the example tables. You can peruse the examples <a href="http://propublica.github.com/table-setter/documentation/tables/">here</a>.</p>
|
44
|
+
<h2><a id="tablesetter" href="#toc">The table-setter command</a></h2>
|
45
|
+
<p>
|
46
|
+
The <strong>table-setter</strong> command responds to three subcommands:
|
47
|
+
<ul>
|
48
|
+
<li><strong>install <DIRECTORY></strong> installs the tablesetter files into the current directory or one you specify.</li>
|
49
|
+
<li><strong>start <DIRECTORY></strong> starts the development server so you can preview your tables before deploying.</li>
|
50
|
+
<li><strong>build <DIRECTORY> -p <PATH></strong> builds a static version of the tables, <strong><PATH></strong> is the relative path where you want to place the tables on your webserver.
|
51
|
+
See <a href="#deployment">Deployment</a></li>
|
52
|
+
</ul>
|
53
|
+
</p>
|
54
|
+
<h2><a id="thedirectory" href="#toc">The Configuration Directory</a></h2>
|
55
|
+
<p>
|
56
|
+
The configuration folder contains the javascripts, stylesheets, view templates (written in <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/">ERB</a>), rackup file, and most importantly the configuration files for each table.
|
57
|
+
</p>
|
58
|
+
<p>You'll put table definition files in the <strong>table</strong> directory, your javascript in <strong>public/javascripts</strong> and css in <strong>public/stylesheets</strong>. You can make most HTML customizations in <strong>views/layout.erb</strong>.
|
59
|
+
<p class="file">
|
60
|
+
The <strong>config.ru</strong> file is a rackup file that instructs the webserver to start the <strong>TableSetter</strong> application and serve the assets contained in the configuration folder. In most cases you'll want to use apache and passenger (see <a href="#deployment">Deployment</a> for details).
|
61
|
+
</p>
|
62
|
+
<p class="dir">
|
63
|
+
In <strong>public</strong> you'll find the static assets required for the look and feel and functionality of the table:
|
64
|
+
</p>
|
65
|
+
<ul>
|
66
|
+
<li class="dir"> The <strong>images</strong> directory contains the small images <img src="template/public/images/th_arrow_asc.gif" style="display:inline"> and <img src="template/public/images/th_arrow_desc.gif" style="display:inline"> which show the user the sorting direction of a given column.</li>
|
67
|
+
<li class="dir"> The <strong>javascripts</strong> directory contains scripts that power the dynamic functionality of a table. Each file depends on <a href="http://jquery.com/">jQuery</a>:
|
68
|
+
<ul>
|
69
|
+
<li class="file"><strong>application.js</strong> dispatches to the other javascript files to render the table at load time. It also defines the column highlighting function.</li>
|
70
|
+
<li class="file"><strong>jquery.tablesorter.js</strong> the jQuery <a href="http://tablesorter.com/docs/">tablesorter plugin</a> that handles the dynamic sorting by column.</li>
|
71
|
+
<li class="file"><strong>jquery.tablesorter.pager.js</strong> the <a href="http://tablesorter.com/docs/example-pager.html">tablesorter pager plugin</a> to tablesorter that provides the paging functionality.</li>
|
72
|
+
<li class="file"><strong>jquery.tablesorter.multipagefilter.js</strong> a custom plugin that allows for searching across multiple pages</li>
|
73
|
+
</ul>
|
74
|
+
</li>
|
75
|
+
<li class="dir">The <strong>stylesheets</strong> directory contains <strong>application.css</strong>, the <strong>TableSetter</strong> stylesheet. Each style is prefaced with <strong>#tablefu</strong> so you should be able to include your organization's css on the page without affecting the tables.</li>
|
76
|
+
</ul>
|
77
|
+
<p class="dir">The <strong>tables</strong> directory contains yml configuration files for each of the tables you want to deploy. By default it contains:</p>
|
78
|
+
<ul>
|
79
|
+
<li class="file"><strong>example.yml</strong> contains most of the simple options in a <strong>TableSetter</strong> file.</li>
|
80
|
+
<li class="file"><strong>example_local.yml</strong> and <strong>example_local.csv</strong> shows how to build a table from a local file. It also is hard_paginated (see <a href="#thefile">A Table Setter File</a>).</li>
|
81
|
+
<li class="file"><strong>example_faceted.yml</strong> is an example of faceting.</li>
|
82
|
+
<li class="file"><strong>example_formatted.yml</strong> and <strong>example_formatted.csv</strong> shows how to apply formatting to a column and a group of columns.</li>
|
83
|
+
</ul>
|
84
|
+
<p class="dir">The <strong>views</strong> directory contains the <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/">ERB</a> templates needed to render the table pages and index page.</p>
|
85
|
+
<ul>
|
86
|
+
<li class="file">
|
87
|
+
<strong>404.erb</strong> and <strong>500.erb</strong> render when a table is not found or a server error occurs, respectively.
|
88
|
+
</li>
|
89
|
+
<li class="file"><strong>layout.erb</strong> contains the basic frame of the page. You should place most of your customizations here. If you'd like to add custom html, place it above or below the <strong><%= yield %></strong> tag.</li>
|
90
|
+
<li class="file"><strong>index.erb</strong> renders the table list for the root path of the app.</li>
|
91
|
+
<li class="file"><strong>table.erb</strong> renders an individual table. You shouldn't have to tweak this much, if at all.</li>
|
92
|
+
</ul>
|
93
|
+
<h2><a id="thefile" href="#toc">A TableSetter File</a></h2>
|
94
|
+
<p>Each TableSetter file is written in <a href="http://www.yaml.org/">YAML</a> and outlines the the display options for a particular table. The filename dictates the path where it will appear (e.g. a config file named example.yml will appear at <strong>http://host/example</strong>). Initially TableSetter installs a few examples to get you started (see <a href="#thedirectory">above</a>).</p>
|
95
|
+
<p>Each table setter file must begin with a <strong>table:</strong> declaration, and it's important to note that whitespace matters. For example consider this csv:</p>
|
96
|
+
<pre>
|
97
|
+
Bank,Spent,Funds,Link
|
98
|
+
McDuck Bank,100000,10000000,http://diveintomoney.com
|
99
|
+
Potter Savings and Loans,1100,1000000,http://angelsandwingsmrstewart.com
|
100
|
+
</pre>
|
101
|
+
<p>these are the example options in a <strong>TableSetter</strong> config file:
|
102
|
+
<pre>
|
103
|
+
table:
|
104
|
+
title: The title of the table
|
105
|
+
|
106
|
+
# google_key:, file:, or url: define how a table is loaded.
|
107
|
+
# only one is necessary
|
108
|
+
file: loads a local CSV file from the /tables directory.
|
109
|
+
url: will load a CSV file from an external server, and
|
110
|
+
google_key: is a google key url from an external google doc (see note).
|
111
|
+
|
112
|
+
deck: A HTML string describing the table, appears above the table itself.
|
113
|
+
|
114
|
+
footer: A HTML string for notes/caveats etc. Appears below the table.
|
115
|
+
|
116
|
+
column_options: # Defines a hash of options that are passed onto TableFu
|
117
|
+
|
118
|
+
columns: # A list of columns to include, for example:
|
119
|
+
- Bank # would only include the bank column in the table
|
120
|
+
|
121
|
+
style: # A list of style declarations by column, for example:
|
122
|
+
Bank: 'text-align:left;' # would left-align the text in the "Bank" column.
|
123
|
+
|
124
|
+
sorted_by: # Defines the sort order and column to sort by of the table.
|
125
|
+
Bank: ascending # would sort by the Bank column in ascending order
|
126
|
+
|
127
|
+
total: # Declares which columns should have a totals row.
|
128
|
+
['Funds', 'Spent']
|
129
|
+
|
130
|
+
formatting: # Defines which of the TableFu formatters to apply to a column.
|
131
|
+
(%) Spent: bar # applies the bar formatter to the '(%) Spent' column.
|
132
|
+
Link: # Creates a meta column form two other columns
|
133
|
+
method: link # describes the formatter to use
|
134
|
+
arguments: ['Bank', 'URL'] # Combines Bank and URL as arguments
|
135
|
+
|
136
|
+
faceting: # Describes the faceting, or grouping, to apply to a table
|
137
|
+
facet_by: Bank # groups the records by bank name
|
138
|
+
|
139
|
+
hard_paginate: true # Dictates that the table should be spread across multiple pages
|
140
|
+
# can't be used with faceting, and disables the user filtering
|
141
|
+
|
142
|
+
per_page: 250 # Instructs TableSetter to only page by 250 rows.
|
143
|
+
|
144
|
+
live: true # publishes the table in the index page. Note that even if live is
|
145
|
+
# set to false the table is still accessible directly.
|
146
|
+
|
147
|
+
</pre>
|
148
|
+
|
149
|
+
<h3>NB: A Note About google_key</h3>
|
150
|
+
<p>At ProPublica, we mainly use TableSetter to format public google spreadsheets. You can find the <strong>google_key</strong> by publishing a spreadsheet as a webpage:</p>
|
151
|
+
<img src="documentation/images/publish.png">
|
152
|
+
<p>and in the dialog box, the google key is here:</p>
|
153
|
+
<img src="documentation/images/key.png">
|
154
|
+
<h2><a id="deployment" href="#toc">Deployment</a></h2>
|
155
|
+
|
156
|
+
<h3>Passenger</h3>
|
157
|
+
<em>(Cribbed from the excellent <a href="http://www.modrails.com/documentation/Users%20guide.html#_deploying_a_rack_based_ruby_application">passenger documentation</a>.)</em>
|
158
|
+
<p>If you're familiar with deploying a Rails application under passenger, not much changes when deploying a rack basked application. <strong>TableSetter</strong> includes a <strong>config.ru</strong> file that should be sufficient under most situations. You'll need to create a <strong>tmp</strong> directory inside the <strong>TableSetter</strong> directory on the server. The following virtual host configuration will deploy <strong>TableSetter</strong> directory:
|
159
|
+
</p>
|
160
|
+
<pre>
|
161
|
+
<VirtualHost *:80>
|
162
|
+
ServerName www.yourdomain.com
|
163
|
+
DocumentRoot /path/to/table-setter/public
|
164
|
+
</VirtualHost></pre>
|
165
|
+
<p>If you want to deploy <strong>TableSetter</strong> under a sub URI you should symlink the public folder to a directory in the document root:</p>
|
166
|
+
<pre>
|
167
|
+
ln -s /path/to/table-setter/public /docroot/tables</pre>
|
168
|
+
<p>
|
169
|
+
and change you're apache config to reflect the sub URI:
|
170
|
+
</p>
|
171
|
+
<pre>
|
172
|
+
<VirtualHost *:80>
|
173
|
+
ServerName www.yourdomain.com
|
174
|
+
DocumentRoot /docroot/tables
|
175
|
+
RackBaseURI /tables
|
176
|
+
</VirtualHost></pre>
|
177
|
+
<h3>Caching</h3>
|
178
|
+
<p>You probably don't want to parse a remote CSV file on every request in production, so the <strong>config.ru</strong> file contains directives to enable <strong>Rack:Cache</strong> a simple reverse proxy cache. If your web server is not behind an upstream cache you'll want to enable it by uncommenting the required lines.<p>
|
179
|
+
<p>You'll also want to enable the <strong>TableSetter:App</strong> expire time by uncommenting this line:</p>
|
180
|
+
<pre>
|
181
|
+
TableSetter::App.cache_timeout = 60 * 15 # 15 minutes</pre>
|
182
|
+
<p>That line dictates the max age of a request and you'll want to tweak it depending on how frequently changed your tables will be and how many users you expect. If you want to define any <a href="https://github.com/propublica/table-fu">TableFu</a> formatters you should do so in <strong>config.ru</strong>.</p>
|
183
|
+
|
184
|
+
<h3>Static</h3>
|
185
|
+
<p>You can also use to pre-build <strong>table-setter</strong> your tables as html and upload the built files to your web server. You can build them using the <strong>table-setter</strong> command:</p>
|
186
|
+
<pre>
|
187
|
+
table-setter build path/to/table-setter/directory -p path</pre>
|
188
|
+
<p>The build tables will be placed in the <strong>out</strong> directory inside the configuration directory.</p>
|
189
|
+
<p>The <strong>-p</strong> flag dictates where on the server relative to root you'll install the files. If I want my tables to appear under the <strong>tables/</strong> directory on my site, I'd run:</p>
|
190
|
+
<pre>
|
191
|
+
table-setter build path/to/table-setter/directory -p tables</pre>
|
192
|
+
<p>And upload the files in the <strong>out/tables</strong> directory.</p>
|
193
|
+
<h2><a id="rails" href="#toc">Rails</a></h2>
|
194
|
+
<p>In order to use table-setter as a Rails, you'll need to install the <a href="http://github.com/propublica/table-setter-generator">table-setter-generator </a> gem. Once you've done that you'll be able to run:</p>
|
195
|
+
<pre>
|
196
|
+
script/generate table-setter</pre>
|
197
|
+
<p>In your existing Rails app path and it will install the <strong>TableSetter</strong> routes, controller, views, and <strong>Table</strong> model.</p>
|
198
|
+
<h2><a id="links" href="#toc">Links</a></h2>
|
199
|
+
<ul>
|
200
|
+
<li><a href="http://github.com/propublica/table-fu">TableFu</a><br>
|
201
|
+
A gem that provides the conceptual backend to <strong>TableSetter</strong>.</li>
|
202
|
+
<li><a href="http://www.modrails.com/documentation/Users%20guide.html#_deploying_a_rack_based_ruby_application">Passenger Documentation</a><br>
|
203
|
+
The Passenger Documention section on how to deploy a rack app under passenger.</li>
|
204
|
+
<li><a href="http://docs.heroku.com/rack">Heroku Documentation</a><br>
|
205
|
+
How to deploy a rack app in heroku.</li>
|
206
|
+
<li><a href="http://github.com/propublica/table-fu/issues">Issues</a><br>
|
207
|
+
The github issue tracker. Post bug reports and feature requests here.</li>
|
208
|
+
<li><a href="http://www.yaml.org/">YAML</a>
|
209
|
+
The YAML homepage. <strong>TableSetter</strong> config files are YAML files.
|
210
|
+
</li>
|
211
|
+
<li><a href="doc/index.html">API Docs</a></li>
|
212
|
+
</ul>
|
213
|
+
<h2><a id="credits" href="#toc">Credits</a></h2>
|
214
|
+
<p><a href="http://github.com/thejefflarson">Jeff Larson</a> (Maintainer), <a href="http://github.com/brianboyer/">Brian Boyer</a>, <a href="http://github.com/kleinmatic">Scott Klein</a>, <a href="http://github.com/markpercival">Mark Percival</a>, and <a href="http://github.com/seebq">Charles Brian Quinn</a>.</p>
|
215
|
+
<h2><a id="license" href="#toc">License</a></h2>
|
216
|
+
<pre>Copyright (c) 2010 ProPublica
|
217
|
+
|
218
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
219
|
+
a copy of this software and associated documentation files (the
|
220
|
+
"Software"), to deal in the Software without restriction, including
|
221
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
222
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
223
|
+
permit persons to whom the Software is furnished to do so, subject to
|
224
|
+
the following conditions:
|
225
|
+
|
226
|
+
The above copyright notice and this permission notice shall be
|
227
|
+
included in all copies or substantial portions of the Software.
|
228
|
+
|
229
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
230
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
231
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
232
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
233
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
234
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
235
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
236
|
+
</pre>
|
237
|
+
</body>
|
238
|
+
</html>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'sinatra/static_assets'
|
2
|
+
require 'sinatra/url_for'
|
3
|
+
|
4
|
+
module TableSetter
|
5
|
+
class App < Sinatra::Base
|
6
|
+
helpers Sinatra::UrlForHelper
|
7
|
+
register Sinatra::StaticAssets
|
8
|
+
set :root, TableSetter.config_path
|
9
|
+
# serve static files from the public directory
|
10
|
+
enable :static
|
11
|
+
|
12
|
+
not_found do
|
13
|
+
show :"404"
|
14
|
+
end
|
15
|
+
|
16
|
+
error do
|
17
|
+
show :"500"
|
18
|
+
end
|
19
|
+
|
20
|
+
get "/" do
|
21
|
+
headers['Cache-Control'] = "public, max-age=#{TableSetter::App.cache_timeout}"
|
22
|
+
last_modified Table.fresh_yaml_time
|
23
|
+
show :index, :tables => Table.all
|
24
|
+
end
|
25
|
+
|
26
|
+
["/:slug/:page/", "/:slug/"].each do |path|
|
27
|
+
get path do
|
28
|
+
headers['Cache-Control'] = "public, max-age=#{TableSetter::App.cache_timeout}"
|
29
|
+
not_found unless Table.exists? params[:slug]
|
30
|
+
table = Table.new(params[:slug], :defer => true)
|
31
|
+
last_modified table.updated_at
|
32
|
+
table.load
|
33
|
+
page = params[:page] || 1
|
34
|
+
table.paginate! page
|
35
|
+
show :table, :table => table, :page => page
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def show(page, locals={})
|
42
|
+
erb page, {:layout => true}, locals
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
attr_accessor :cache_timeout
|
47
|
+
|
48
|
+
def cache_timeout
|
49
|
+
@cache_timeout || 0
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|