footable-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+ FooTable-src
20
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bootstrap-rails.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ FooTable-rails
2
+ ==============
3
+
4
+ footable-rails integrates [FooTable](https://github.com/bradvin/FooTable) in Rails assets pipeline.
5
+
6
+
7
+ ```
8
+ gem 'footable-rails'
9
+ ```
10
+
11
+ application.css
12
+
13
+ ````sass
14
+ *= require footable-rails
15
+ ```
16
+
17
+ application.js
18
+ ```
19
+ //= require footable-rails
20
+ ```
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env rake
2
+ require File.expand_path('../lib/footable-rails/version', __FILE__)
3
+
4
+ desc "Update assets"
5
+ task :update do
6
+ system("rm -rf FooTable-src")
7
+ system("git clone git://github.com/bradvin/FooTable.git FooTable-src")
8
+ system("git status")
9
+ end
10
+
11
+ desc "Build"
12
+ task "build" do
13
+ system("gem build footable-rails.gemspec")
14
+ end
15
+
16
+ desc "Build and publish the gem"
17
+ task :publish => :build do
18
+ system("gem push footable-rails-#{FootableRails::Rails::VERSION}.gem")
19
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/footable-rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Gonzalo Rodríguez-Baltanás Díaz"]
6
+ gem.email = ["siotopo@gmail.com"]
7
+ gem.description = %q{Plugin for unobstrusive tables }
8
+ gem.homepage = "https://github.com/Nerian/FooTable-rails"
9
+ gem.summary = gem.description
10
+
11
+ gem.name = "footable-rails"
12
+ gem.require_paths = ["lib"]
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.version = FootableRails::Rails::VERSION
15
+
16
+ gem.add_dependency "railties", ">= 3.0"
17
+ gem.add_development_dependency "bundler", ">= 1.0"
18
+ gem.add_development_dependency "rake"
19
+ end
@@ -0,0 +1,12 @@
1
+ require "rails"
2
+ require "footable-rails/version"
3
+
4
+ module FootableRails
5
+ module Rails
6
+ if ::Rails.version < "3.1"
7
+ require "footable-rails/railtie"
8
+ else
9
+ require "footable-rails/engine"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module FootableRails
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module FootableRails
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module FootableRails
2
+ module Rails
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,403 @@
1
+ /*!
2
+ * FooTable - Awesome Responsive Tables
3
+ * http://themergency.com/footable
4
+ *
5
+ * Requires jQuery - http://jquery.com/
6
+ *
7
+ * Copyright 2012 Steven Usher & Brad Vincent
8
+ * Released under the MIT license
9
+ * You are free to use FooTable in commercial projects as long as this copyright header is left intact.
10
+ *
11
+ * Date: 18 Nov 2012
12
+ */
13
+ (function ($, w, undefined) {
14
+ w.footable = {
15
+ options: {
16
+ delay: 100, // The number of millseconds to wait before triggering the react event
17
+ breakpoints: { // The different screen resolution breakpoints
18
+ phone: 480,
19
+ tablet: 1024
20
+ },
21
+ parsers: { // The default parser to parse the value out of a cell (values are used in building up row detail)
22
+ alpha: function (cell) {
23
+ return $(cell).data('value') || $.trim($(cell).text());
24
+ }
25
+ },
26
+ toggleSelector: ' > tbody > tr:not(.footable-row-detail)', //the selector to show/hide the detail row
27
+ createDetail: function (element, data) { //creates the contents of the detail row
28
+ for (var i = 0; i < data.length; i++) {
29
+ element.append('<div><strong>' + data[i].name + '</strong> : ' + data[i].display + '</div>');
30
+ }
31
+ },
32
+ classes: {
33
+ loading : 'footable-loading',
34
+ loaded : 'footable-loaded',
35
+ sorted : 'footable-sorted',
36
+ descending : 'footable-sorted-desc',
37
+ indicator : 'footable-sort-indicator'
38
+ },
39
+ debug: false // Whether or not to log information to the console.
40
+ },
41
+
42
+ version: {
43
+ major: 0, minor: 1,
44
+ toString: function () {
45
+ return w.footable.version.major + '.' + w.footable.version.minor;
46
+ },
47
+ parse: function (str) {
48
+ version = /(\d+)\.?(\d+)?\.?(\d+)?/.exec(str);
49
+ return {
50
+ major: parseInt(version[1]) || 0,
51
+ minor: parseInt(version[2]) || 0,
52
+ patch: parseInt(version[3]) || 0
53
+ };
54
+ }
55
+ },
56
+
57
+ plugins: {
58
+ _validate: function (plugin) {
59
+ ///<summary>Simple validation of the <paramref name="plugin"/> to make sure any members called by Foobox actually exist.</summary>
60
+ ///<param name="plugin">The object defining the plugin, this should implement a string property called "name" and a function called "init".</param>
61
+
62
+ if (typeof plugin['name'] !== 'string') {
63
+ if (w.footable.options.debug == true) console.error('Validation failed, plugin does not implement a string property called "name".', plugin);
64
+ return false;
65
+ }
66
+ if (!$.isFunction(plugin['init'])) {
67
+ if (w.footable.options.debug == true) console.error('Validation failed, plugin "' + plugin['name'] + '" does not implement a function called "init".', plugin);
68
+ return false;
69
+ }
70
+ if (w.footable.options.debug == true) console.log('Validation succeeded for plugin "' + plugin['name'] + '".', plugin);
71
+ return true;
72
+ },
73
+ registered: [], // An array containing all registered plugins.
74
+ register: function (plugin, options) {
75
+ ///<summary>Registers a <paramref name="plugin"/> and its default <paramref name="options"/> with Foobox.</summary>
76
+ ///<param name="plugin">The plugin that should implement a string property called "name" and a function called "init".</param>
77
+ ///<param name="options">The default options to merge with the Foobox's base options.</param>
78
+
79
+ if (w.footable.plugins._validate(plugin)) {
80
+ w.footable.plugins.registered.push(plugin);
81
+ if (options != undefined && typeof options === 'object') $.extend(true, w.footable.options, options);
82
+ if (w.footable.options.debug == true) console.log('Plugin "' + plugin['name'] + '" has been registered with the Foobox.', plugin);
83
+ }
84
+ },
85
+ init: function (instance) {
86
+ ///<summary>Loops through all registered plugins and calls the "init" method supplying the current <paramref name="instance"/> of the Foobox as the first parameter.</summary>
87
+ ///<param name="instance">The current instance of the Foobox that the plugin is being initialized for.</param>
88
+
89
+ for(var i = 0; i < w.footable.plugins.registered.length; i++){
90
+ try {
91
+ w.footable.plugins.registered[i]['init'](instance);
92
+ } catch(err) {
93
+ if (w.footable.options.debug == true) console.error(err);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ };
99
+
100
+ var instanceCount = 0;
101
+
102
+ $.fn.footable = function(options) {
103
+ ///<summary>The main constructor call to initialize the plugin using the supplied <paramref name="options"/>.</summary>
104
+ ///<param name="options">
105
+ ///<para>A JSON object containing user defined options for the plugin to use. Any options not supplied will have a default value assigned.</para>
106
+ ///<para>Check the documentation or the default options object above for more information on available options.</para>
107
+ ///</param>
108
+
109
+ options=options||{};
110
+ var o=$.extend(true,{},w.footable.options,options); //merge user and default options
111
+ return this.each(function () {
112
+ instanceCount++;
113
+ this.footable = new Footable(this, o, instanceCount);
114
+ });
115
+ };
116
+
117
+ //helper for using timeouts
118
+ function Timer() {
119
+ ///<summary>Simple timer object created around a timeout.</summary>
120
+ var t=this;
121
+ t.id=null;
122
+ t.busy=false;
123
+ t.start=function (code,milliseconds) {
124
+ ///<summary>Starts the timer and waits the specified amount of <paramref name="milliseconds"/> before executing the supplied <paramref name="code"/>.</summary>
125
+ ///<param name="code">The code to execute once the timer runs out.</param>
126
+ ///<param name="milliseconds">The time in milliseconds to wait before executing the supplied <paramref name="code"/>.</param>
127
+
128
+ if (t.busy) {return;}
129
+ t.stop();
130
+ t.id=setTimeout(function () {
131
+ code();
132
+ t.id=null;
133
+ t.busy=false;
134
+ },milliseconds);
135
+ t.busy=true;
136
+ };
137
+ t.stop=function () {
138
+ ///<summary>Stops the timer if its runnning and resets it back to its starting state.</summary>
139
+
140
+ if(t.id!=null) {
141
+ clearTimeout(t.id);
142
+ t.id=null;
143
+ t.busy=false;
144
+ }
145
+ };
146
+ };
147
+
148
+ function Footable(t, o, id) {
149
+ ///<summary>Inits a new instance of the plugin.</summary>
150
+ ///<param name="t">The main table element to apply this plugin to.</param>
151
+ ///<param name="o">The options supplied to the plugin. Check the defaults object to see all available options.</param>
152
+ ///<param name="id">The id to assign to this instance of the plugin.</param>
153
+
154
+ var ft = this;
155
+ ft.id = id;
156
+ ft.table = t;
157
+ ft.options = o;
158
+ ft.breakpoints = [];
159
+ ft.breakpointNames = '';
160
+ ft.columns = { };
161
+
162
+ var opt = ft.options;
163
+ var cls = opt.classes;
164
+
165
+ // This object simply houses all the timers used in the footable.
166
+ ft.timers = {
167
+ resize: new Timer(),
168
+ register: function (name) {
169
+ ft.timers[name] = new Timer();
170
+ return ft.timers[name];
171
+ }
172
+ };
173
+
174
+ w.footable.plugins.init(ft);
175
+
176
+ ft.init = function() {
177
+ var $window = $(w), $table = $(ft.table);
178
+
179
+ if ($table.hasClass(cls.loaded)) {
180
+ //already loaded FooTable for the table, so don't init again
181
+ ft.raise('footable_already_initialized');
182
+ return;
183
+ }
184
+
185
+ $table.addClass(cls.loading);
186
+
187
+ // Get the column data once for the life time of the plugin
188
+ $table.find('> thead > tr > th, > thead > tr > td').each(function() {
189
+ var data = ft.getColumnData(this);
190
+ ft.columns[data.index] = data;
191
+
192
+ var count = data.index + 1;
193
+ //get all the cells in the column
194
+ var $column = $table.find('> tbody > tr > td:nth-child(' + count + ')');
195
+ //add the className to the cells specified by data-class="blah"
196
+ if (data.className != null) $column.not('.footable-cell-detail').addClass(data.className);
197
+ });
198
+
199
+ // Create a nice friendly array to work with out of the breakpoints object.
200
+ for(var name in opt.breakpoints) {
201
+ ft.breakpoints.push({ 'name': name, 'width': opt.breakpoints[name] });
202
+ ft.breakpointNames += (name + ' ');
203
+ }
204
+
205
+ // Sort the breakpoints so the smallest is checked first
206
+ ft.breakpoints.sort(function(a, b) { return a['width'] - b['width']; });
207
+
208
+ //bind the toggle selector click events
209
+ ft.bindToggleSelectors();
210
+
211
+ ft.raise('footable_initializing');
212
+
213
+ $table.bind('footable_initialized', function (e) {
214
+ //resize the footable onload
215
+ ft.resize();
216
+
217
+ //remove the loading class
218
+ $table.removeClass(cls.loading);
219
+
220
+ //hides all elements within the table that have the attribute data-hide="init"
221
+ $table.find('[data-init="hide"]').hide();
222
+ $table.find('[data-init="show"]').show();
223
+
224
+ //add the loaded class
225
+ $table.addClass(cls.loaded);
226
+ });
227
+
228
+ $window
229
+ .bind('resize.footable', function () {
230
+ ft.timers.resize.stop();
231
+ ft.timers.resize.start(function() {
232
+ ft.raise('footable_resizing');
233
+ ft.resize();
234
+ ft.raise('footable_resized');
235
+ }, opt.delay);
236
+ });
237
+
238
+ ft.raise('footable_initialized');
239
+ };
240
+
241
+ //moved this out into it's own function so that it can be called from other add-ons
242
+ ft.bindToggleSelectors = function() {
243
+ var $table = $(ft.table);
244
+ $table.find(opt.toggleSelector).unbind('click.footable').bind('click.footable', function (e) {
245
+ if ($table.is('.breakpoint')) {
246
+ var $row = $(this).is('tr') ? $(this) : $(this).parents('tr:first');
247
+ ft.toggleDetail($row.get(0));
248
+ }
249
+ });
250
+ };
251
+
252
+ ft.parse = function(cell, column) {
253
+ var parser = opt.parsers[column.type] || opt.parsers.alpha;
254
+ return parser(cell);
255
+ };
256
+
257
+ ft.getColumnData = function(th) {
258
+ var $th = $(th), hide = $th.data('hide');
259
+ hide = hide || '';
260
+ hide = hide.split(',');
261
+ var data = {
262
+ 'index': $th.index(),
263
+ 'hide': { },
264
+ 'type': $th.data('type') || 'alpha',
265
+ 'name': $th.data('name') || $.trim($th.text()),
266
+ 'ignore': $th.data('ignore') || false,
267
+ 'className': $th.data('class') || null
268
+ };
269
+ data.hide['default'] = ($th.data('hide')==="all") || ($.inArray('default', hide) >= 0);
270
+
271
+ for(var name in opt.breakpoints) {
272
+ data.hide[name] = ($th.data('hide')==="all") || ($.inArray(name, hide) >= 0);
273
+ }
274
+ var e = ft.raise('footable_column_data', { 'column': { 'data': data, 'th': th } });
275
+ return e.column.data;
276
+ };
277
+
278
+ ft.getViewportWidth = function() {
279
+ return window.innerWidth || (document.body ? document.body.offsetWidth : 0);
280
+ };
281
+
282
+ ft.getViewportHeight = function() {
283
+ return window.innerHeight || (document.body ? document.body.offsetHeight : 0);
284
+ };
285
+
286
+ ft.hasBreakpointColumn = function(breakpoint) {
287
+ for(var c in ft.columns) {
288
+ if (ft.columns[c].hide[breakpoint]) {
289
+ return true;
290
+ }
291
+ }
292
+ return false;
293
+ };
294
+
295
+ ft.resize = function() {
296
+ var $table = $(ft.table);
297
+ var info = {
298
+ 'width': $table.width(), //the table width
299
+ 'height': $table.height(), //the table height
300
+ 'viewportWidth': ft.getViewportWidth(), //the width of the viewport
301
+ 'viewportHeight': ft.getViewportHeight(), //the width of the viewport
302
+ 'orientation': null
303
+ };
304
+ info.orientation = info.viewportWidth > info.viewportHeight ? 'landscape' : 'portrait';
305
+
306
+ if (info.viewportWidth < info.width) info.width = info.viewportWidth;
307
+ if (info.viewportHeight < info.height) info.height = info.viewportHeight;
308
+
309
+ var pinfo = $table.data('footable_info');
310
+ $table.data('footable_info', info);
311
+
312
+ // This (if) statement is here purely to make sure events aren't raised twice as mobile safari seems to do
313
+ if (!pinfo || ((pinfo && pinfo.width && pinfo.width != info.width) || (pinfo && pinfo.height && pinfo.height != info.height))) {
314
+ var current = null, breakpoint;
315
+ for (var i = 0; i < ft.breakpoints.length; i++) {
316
+ breakpoint = ft.breakpoints[i];
317
+ if (breakpoint && breakpoint.width && info.width <= breakpoint.width) {
318
+ current = breakpoint;
319
+ break;
320
+ }
321
+ }
322
+
323
+ var breakpointName = (current == null ? 'default' : current['name']);
324
+
325
+ var hasBreakpointFired = ft.hasBreakpointColumn(breakpointName);
326
+
327
+ $table
328
+ .removeClass('default breakpoint').removeClass(ft.breakpointNames)
329
+ .addClass(breakpointName + (hasBreakpointFired ? ' breakpoint' : ''))
330
+ .find('> thead > tr > th').each(function() {
331
+ var data = ft.columns[$(this).index()];
332
+ var count = data.index + 1;
333
+ //get all the cells in the column
334
+ var $column = $table.find('> tbody > tr > td:nth-child(' + count + '), > tfoot > tr > td:nth-child(' + count + '), > colgroup > col:nth-child(' + count + ')').add(this);
335
+
336
+ if (data.hide[breakpointName] == false) $column.show();
337
+ else $column.hide();
338
+ })
339
+ .end()
340
+ .find('> tbody > tr.footable-detail-show').each(function() {
341
+ ft.createOrUpdateDetailRow(this);
342
+ });
343
+
344
+ $table.find('> tbody > tr.footable-detail-show:visible').each(function() {
345
+ var $next = $(this).next();
346
+ if ($next.hasClass('footable-row-detail')) {
347
+ if (breakpointName == 'default' && !hasBreakpointFired) $next.hide();
348
+ else $next.show();
349
+ }
350
+ });
351
+
352
+ ft.raise('footable_breakpoint_' + breakpointName, { 'info': info });
353
+ }
354
+ };
355
+
356
+ ft.toggleDetail = function(actualRow) {
357
+ var $row = $(actualRow),
358
+ created = ft.createOrUpdateDetailRow($row.get(0)),
359
+ $next = $row.next();
360
+
361
+ if (!created && $next.is(':visible')) {
362
+ $row.removeClass('footable-detail-show');
363
+ $next.hide();
364
+ } else {
365
+ $row.addClass('footable-detail-show');
366
+ $next.show();
367
+ }
368
+ };
369
+
370
+ ft.createOrUpdateDetailRow = function (actualRow) {
371
+ var $row = $(actualRow), $next = $row.next(), $detail, values = [];
372
+ if ($row.is(':hidden')) return; //if the row is hidden for some readon (perhaps filtered) then get out of here
373
+ $row.find('> td:hidden').each(function () {
374
+ var column = ft.columns[$(this).index()];
375
+ if (column.ignore == true) return true;
376
+ values.push({ 'name': column.name, 'value': ft.parse(this, column), 'display': $.trim($(this).html()) });
377
+ });
378
+ var colspan = $row.find('> td:visible').length;
379
+ var exists = $next.hasClass('footable-row-detail');
380
+ if (!exists) { // Create
381
+ $next = $('<tr class="footable-row-detail"><td class="footable-cell-detail"><div class="footable-row-detail-inner"></div></td></tr>');
382
+ $row.after($next);
383
+ }
384
+ $next.find('> td:first').attr('colspan', colspan);
385
+ $detail = $next.find('.footable-row-detail-inner').empty();
386
+ opt.createDetail($detail, values);
387
+ return !exists;
388
+ };
389
+
390
+ ft.raise = function(eventName, args) {
391
+ args = args || { };
392
+ var def = { 'ft': ft };
393
+ $.extend(true, def, args);
394
+ var e = $.Event(eventName, def);
395
+ if (!e.ft) { $.extend(true, e, def); } //pre jQuery 1.6 which did not allow data to be passed to event object constructor
396
+ $(ft.table).trigger(e);
397
+ return e;
398
+ };
399
+
400
+ ft.init();
401
+ return ft;
402
+ };
403
+ })(jQuery, window);
@@ -0,0 +1,2 @@
1
+ //= require ./footable
2
+ //= require_tree ./plugins/
@@ -0,0 +1,81 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable == undefined || w.footable == null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var jQversion = w.footable.version.parse($.fn.jquery);
6
+ if (jQversion.major == 1 && jQversion.minor < 8) { // For older versions of jQuery, anything below 1.8
7
+ $.expr[':'].ftcontains = function(a, i, m) {
8
+ return $(a).html().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
9
+ };
10
+ } else { // For jQuery 1.8 and above
11
+ $.expr[":"].ftcontains = $.expr.createPseudo(function(arg) {
12
+ return function(elem) {
13
+ return $(elem).html().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
14
+ };
15
+ });
16
+ }
17
+
18
+ var defaults = {
19
+ filter: {
20
+ enabled: true,
21
+ input: '.footable-filter',
22
+ timeout: 300,
23
+ minimum: 2
24
+ }
25
+ };
26
+
27
+ function Filter() {
28
+ var p = this;
29
+ p.name = 'Footable Filter';
30
+ p.init = function(ft) {
31
+ if (ft.options.filter.enabled == true) {
32
+ ft.timers.register('filter');
33
+ $(ft.table).bind({
34
+ 'footable_initialized': function(e) {
35
+ var $table = $(e.ft.table);
36
+ var data = {
37
+ 'input': $table.data('filter') || e.ft.options.filter.input,
38
+ 'timeout': $table.data('filter-timeout') || e.ft.options.filter.timeout,
39
+ 'minimum': $table.data('filter-minimum') || e.ft.options.filter.minimum
40
+ };
41
+ $(data.input).keyup(function () {
42
+ e.ft.timers.filter.stop();
43
+ e.ft.timers.filter.start(function() {
44
+ var val = $(data.input).val() || '';
45
+ if (val.length < data.minimum) {
46
+ $table.find("> tbody > tr:not(.footable-row-detail)").each(function() {
47
+ p.showRow(this, e.ft);
48
+ });
49
+ } else {
50
+ var filters = val.split(" ");
51
+ $table.find("> tbody > tr").hide();
52
+ var rows = $table.find("> tbody > tr:not(.footable-row-detail)");
53
+ $.each(filters, function(i, f) {
54
+ if (f && f.length)
55
+ rows = rows.filter("*:ftcontains('" + f + "')");
56
+ });
57
+ rows.each(function() {
58
+ p.showRow(this, e.ft);
59
+ });
60
+ }
61
+ }, data.timeout);
62
+ });
63
+ }
64
+ });
65
+ }
66
+ };
67
+
68
+ p.showRow = function(row, ft) {
69
+ var $row = $(row), $next = $row.next(), $table = $(ft.table);
70
+ if ($row.is(':visible')) return; //already visible - do nothing
71
+ if ($table.hasClass('breakpoint') && $row.hasClass('footable-detail-show') && $next.hasClass('footable-row-detail')) {
72
+ $row.add($next).show();
73
+ ft.createOrUpdateDetailRow(row);
74
+ }
75
+ else $row.show();
76
+ };
77
+ };
78
+
79
+ w.footable.plugins.register(new Filter(), defaults);
80
+
81
+ })(jQuery, window);
@@ -0,0 +1,44 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable == undefined || w.foobox == null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var defaults = {
6
+ /*
7
+ Plugin options here, example:
8
+
9
+ var defaults = {
10
+ myPlugin: {
11
+ enabled: true
12
+ }
13
+ };
14
+
15
+ This would allow you to access this option using ft.options.myPlugin.enabled
16
+ */
17
+ };
18
+
19
+ function MyPlugin() {
20
+ var p = this;
21
+ p.name = 'Footable MyPlugin';
22
+ p.init = function(ft) {
23
+ $(ft.table).bind({
24
+ /*
25
+ Bind to relevant events here to modify/add functionality to Footable, example:
26
+
27
+ $(ft.table).bind({
28
+ 'footable_initialized': function(e){
29
+ if (e.ft.options.myPlugin.enabled == true){
30
+ alert('Hello World');
31
+ }
32
+ }
33
+ });
34
+
35
+ This would listen for the 'footable_initialized' event and when called check if the plugin is enabled
36
+ and if it is alert 'Hello World' to the user.
37
+ */
38
+ });
39
+ };
40
+ };
41
+
42
+ w.footable.plugins.register(new MyPlugin(), defaults);
43
+
44
+ })(jQuery, window);
@@ -0,0 +1,153 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable == undefined || w.footable == null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var defaults = {
6
+ sort: true,
7
+ sorters: {
8
+ alpha: function (a, b) {
9
+ if (a[0] == b[0]) return 0;
10
+ if (a[0] < b[0]) return -1;
11
+ return 1;
12
+ },
13
+ numeric: function (a, b) {
14
+ return a - b;
15
+ }
16
+ },
17
+ parsers: {
18
+ numeric: function (cell) {
19
+ var val = $(cell).data('value') || $(cell).text().replace(/[^0-9.-]/g, '');
20
+ val = parseFloat(val);
21
+ if (isNaN(val)) val = 0;
22
+ return val;
23
+ }
24
+ },
25
+ classes: {
26
+ sort: {
27
+ sortable : 'footable-sortable',
28
+ sorted : 'footable-sorted',
29
+ descending : 'footable-sorted-desc',
30
+ indicator : 'footable-sort-indicator'
31
+ }
32
+ }
33
+ };
34
+
35
+ function Sortable() {
36
+ var p = this;
37
+ p.name = 'Footable Sortable';
38
+ p.init = function(ft) {
39
+ if (ft.options.sort == true) {
40
+ $(ft.table).bind({
41
+ 'footable_initialized': function(e) {
42
+ var cls = ft.options.classes.sort;
43
+
44
+ var $table = $(e.ft.table), $tbody = $table.find('> tbody');
45
+
46
+ $(e.ft.table).find('tr th').each(function (ec) {
47
+ var $th = $(this);
48
+ var column = e.ft.columns[$th.index()];
49
+ if (column.sort.ignore != true) {
50
+ $th.addClass(cls.sortable);
51
+ $('<span />').addClass(cls.indicator).appendTo($th);
52
+ }
53
+ });
54
+
55
+ $(e.ft.table).find('tr th.' + cls.sortable).click(function (ec) {
56
+ var $th = $(this), index = $th.index();
57
+ var column = e.ft.columns[index];
58
+ if (column.sort.ignore == true) return true;
59
+ ec.preventDefault();
60
+
61
+ $table.find('> thead > tr > th').not($th).removeClass(cls.sorted + ' ' + cls.descending);
62
+
63
+ if ($th.hasClass(cls.sorted)) {
64
+ p.reverse(e.ft, $tbody);
65
+ $th.removeClass(cls.sorted).addClass(cls.descending);
66
+ } else if ($th.hasClass(cls.descending)) {
67
+ p.reverse(e.ft, $tbody);
68
+ $th.removeClass(cls.descending).addClass(cls.sorted);
69
+ } else {
70
+ p.sort(e.ft, $tbody, column);
71
+ $th.removeClass(cls.descending).addClass(cls.sorted);
72
+ }
73
+ e.ft.bindToggleSelectors();
74
+ return false;
75
+ });
76
+
77
+ var didSomeSorting = false;
78
+ for(var c in e.ft.columns) {
79
+ var column = e.ft.columns[c];
80
+ if (column.sort.initial) {
81
+ p.sort(e.ft, $tbody, column);
82
+ didSomeSorting = true;
83
+ var $th = $table.find('thead th:eq(' + c + ')');
84
+
85
+ if (column.sort.initial == "descending") {
86
+ p.reverse(e.ft, $tbody);
87
+ $th.addClass(cls.descending);
88
+ } else {
89
+ $th.addClass(cls.sorted);
90
+ }
91
+
92
+ break;
93
+ } else if (column.sort.ignore != true) {
94
+
95
+ }
96
+ }
97
+ if (didSomeSorting) { e.ft.bindToggleSelectors(); }
98
+ },
99
+ 'footable_column_data': function(e) {
100
+ var $th = $(e.column.th);
101
+ e.column.data.sort = e.column.data.sort || { };
102
+ e.column.data.sort.initial = $th.data('sort-initial') || false;
103
+ e.column.data.sort.ignore = $th.data('sort-ignore') || false;
104
+ e.column.data.sort.selector = $th.data('sort-selector') || null;
105
+ }
106
+ });
107
+ }
108
+ };
109
+
110
+ p.rows = function(ft, tbody, column) {
111
+ var rows = [];
112
+ tbody.find('> tr').each(function () {
113
+ var $row = $(this), $next = null;
114
+ if ($row.hasClass('footable-row-detail')) return true;
115
+ if ($row.next().hasClass('footable-row-detail')) {
116
+ $next = $row.next().get(0);
117
+ }
118
+ var row = { 'row': $row, 'detail': $next };
119
+ if (column != undefined && column.index != undefined) {
120
+ row.value = ft.parse(this.cells[column.index], column);
121
+ }
122
+ rows.push(row);
123
+ return true;
124
+ }).remove();
125
+ return rows;
126
+ };
127
+
128
+ p.sort = function(ft, tbody, column) {
129
+ var rows = p.rows(ft, tbody, column);
130
+ var sorter = ft.options.sorters[column.type] || ft.options.sorters.alpha;
131
+ rows.sort(function(a, b) { return sorter(a.value, b.value); });
132
+ for (var j = 0; j < rows.length; j++) {
133
+ tbody.append(rows[j].row);
134
+ if (rows[j].detail != null) {
135
+ tbody.append(rows[j].detail);
136
+ }
137
+ }
138
+ };
139
+
140
+ p.reverse = function(ft, tbody) {
141
+ var rows = p.rows(ft, tbody);
142
+ for (var i = rows.length - 1; i >= 0; i--) {
143
+ tbody.append(rows[i].row);
144
+ if (rows[i].detail != null) {
145
+ tbody.append(rows[i].detail);
146
+ }
147
+ }
148
+ };
149
+ };
150
+
151
+ w.footable.plugins.register(new Sortable(), defaults);
152
+
153
+ })(jQuery, window);
@@ -0,0 +1,92 @@
1
+ .footable > thead > tr > th,.footable > thead > tr > td {
2
+ position: relative;
3
+ }
4
+
5
+ .footable {
6
+ border-spacing: 0;
7
+ width: 100%;
8
+ border: solid #ccc 1px;
9
+ -moz-border-radius: 6px;
10
+ -webkit-border-radius: 6px;
11
+ border-radius: 6px;
12
+ font-family: 'trebuchet MS' , 'Lucida sans' , Arial;
13
+ font-size: 14px;
14
+ color: #444;
15
+ }
16
+
17
+ .footable.breakpoint > tbody > tr > td.expand {
18
+ background: url('assets/images/plus.png') no-repeat 5px center;
19
+ padding-left: 40px;
20
+ }
21
+
22
+ .footable.breakpoint > tbody > tr.footable-detail-show > td.expand {
23
+ background: url('assets/images/minus.png') no-repeat 5px center;
24
+ }
25
+
26
+ .footable.breakpoint > tbody > tr.footable-row-detail {
27
+ background: #eee;
28
+ }
29
+
30
+ .footable > tbody > tr:hover {
31
+ background: #fbf8e9;
32
+ }
33
+
34
+ .footable.breakpoint > tbody > tr:hover:not(.footable-row-detail) {
35
+ cursor: pointer;
36
+ }
37
+
38
+ .footable > tbody > tr > td, .footable > thead > tr > th {
39
+ border-left: 1px solid #ccc;
40
+ border-top: 1px solid #ccc;
41
+ padding: 10px;
42
+ text-align: left;
43
+ }
44
+
45
+ .footable > thead > tr > th, .footable > thead > tr > td {
46
+ background-color: #dce9f9;
47
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ebf3fc), to(#dce9f9));
48
+ background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9);
49
+ background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9);
50
+ background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9);
51
+ background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9);
52
+ background-image: linear-gradient(to bottom, #ebf3fc, #dce9f9);
53
+ -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
54
+ -moz-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
55
+ box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
56
+ border-top: none;
57
+ text-shadow: 0 1px 0 rgba(255,255,255,.5);
58
+ }
59
+
60
+ .footable > thead > tr > th:first-child, .footable > thead > tr > td:first-child {
61
+ -moz-border-radius: 6px 0 0 0;
62
+ -webkit-border-radius: 6px 0 0 0;
63
+ border-radius: 6px 0 0 0;
64
+ }
65
+
66
+ .footable > thead > tr > th:last-child, .footable > thead > tr > td:last-child {
67
+ -moz-border-radius: 0 6px 0 0;
68
+ -webkit-border-radius: 0 6px 0 0;
69
+ border-radius: 0 6px 0 0;
70
+ }
71
+
72
+ .footable > thead > tr > th:only-child, .footable > thead > tr > td:only-child {
73
+ -moz-border-radius: 6px 6px 0 0;
74
+ -webkit-border-radius: 6px 6px 0 0;
75
+ border-radius: 6px 6px 0 0;
76
+ }
77
+
78
+ .footable > tbody > tr:last-child > td:first-child {
79
+ -moz-border-radius: 0 0 0 6px;
80
+ -webkit-border-radius: 0 0 0 6px;
81
+ border-radius: 0 0 0 6px;
82
+ }
83
+
84
+ .footable > tbody > tr:last-child > td:last-child {
85
+ -moz-border-radius: 0 0 6px 0;
86
+ -webkit-border-radius: 0 0 6px 0;
87
+ border-radius: 0 0 6px 0;
88
+ }
89
+
90
+ .footable > tbody img {
91
+ vertical-align:middle;
92
+ }
@@ -0,0 +1,2 @@
1
+ *= require ./footable
2
+ *= require_tree ./plugins/
@@ -0,0 +1,24 @@
1
+ .footable > thead > tr > th > span.footable-sort-indicator {
2
+ width: 16px;
3
+ height: 16px;
4
+ display: block;
5
+ float:right;
6
+ background: url('assets/images/sorting_sprite.png') no-repeat top left;
7
+ }
8
+
9
+ .footable > thead > tr > th.footable-sortable:hover {
10
+ cursor:pointer;
11
+ }
12
+
13
+ .footable > thead > tr > th.footable-sortable > span {
14
+
15
+ }
16
+
17
+ .footable > thead > tr > th.footable-sorted > span.footable-sort-indicator {
18
+ background-position: 0 -16px;
19
+ }
20
+
21
+ .footable > thead > tr > th.footable-sorted-desc > span.footable-sort-indicator {
22
+ background-position: 0 -32px;
23
+ }
24
+
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: footable-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gonzalo Rodríguez-Baltanás Díaz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: ! 'Plugin for unobstrusive tables '
63
+ email:
64
+ - siotopo@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - README.md
72
+ - Rakefile.rb
73
+ - footable-rails.gemspec
74
+ - lib/footable-rails.rb
75
+ - lib/footable-rails/engine.rb
76
+ - lib/footable-rails/railtie.rb
77
+ - lib/footable-rails/version.rb
78
+ - vendor/assets/images/footable-rails/down.png
79
+ - vendor/assets/images/footable-rails/minus.png
80
+ - vendor/assets/images/footable-rails/plus.png
81
+ - vendor/assets/images/footable-rails/sorting_sprite.png
82
+ - vendor/assets/images/footable-rails/up.png
83
+ - vendor/assets/javascripts/footable-rails/footable.js
84
+ - vendor/assets/javascripts/footable-rails/index.js
85
+ - vendor/assets/javascripts/footable-rails/plugins/filter/footable.filter.js
86
+ - vendor/assets/javascripts/footable-rails/plugins/filter/footable.plugin.template.js
87
+ - vendor/assets/javascripts/footable-rails/plugins/sortable/footable.sortable.js
88
+ - vendor/assets/stylesheets/footable-rails/footable.css
89
+ - vendor/assets/stylesheets/footable-rails/index.css
90
+ - vendor/assets/stylesheets/footable-rails/plugins/sortable/footable.sortable.css
91
+ homepage: https://github.com/Nerian/FooTable-rails
92
+ licenses: []
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ segments:
104
+ - 0
105
+ hash: 1224216804177223604
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ segments:
113
+ - 0
114
+ hash: 1224216804177223604
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Plugin for unobstrusive tables
121
+ test_files: []