footable-rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []