osom-tables 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +147 -0
- data/lib/osom-tables.rb +6 -0
- data/lib/osom_tables.rb +3 -0
- data/lib/osom_tables/helper.rb +91 -0
- data/lib/osom_tables/railtie.rb +16 -0
- data/vendor/assets/images/osom-tables-spinner.gif +0 -0
- data/vendor/assets/javascripts/osom-tables.js +104 -0
- data/vendor/assets/stylesheets/osom-tables.css.scss +88 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5fd6cce444e1be672327791d4721d373553335f8
|
4
|
+
data.tar.gz: facda0539d1e13e51ae6844b22d93c2cb814e2cb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4524680c19d243df750a93e986406db7de9edb56b4af6b8e07ab2e6327dbf76620a810f807db89e460a9fdc5a769d6efa5208713455c9e61a4beb8f9aefd9a0
|
7
|
+
data.tar.gz: 96141a88e8fe9fe7f22a00ae24587e83bf58efe78d37363fa898184794b8ea38c47a592203ab84507ffee74a18e1ae1c17aac86e0ce1d90e6e978b872dff886e
|
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# OsomTables
|
2
|
+
|
3
|
+
Ajax tables engine that respects MVC and goes well with the rails way.
|
4
|
+
|
5
|
+
## The Merits
|
6
|
+
|
7
|
+
1. Rails friendly, relies on partials, scopes, etc.
|
8
|
+
2. Respects MVC, views are for views, models are for models
|
9
|
+
3. Flexible, you write your views in templates and paint them as you pleased
|
10
|
+
4. Unit testable, every moving part is independent and unit-testable
|
11
|
+
5. Light footprint, the whole thing is less than 100 lines of JS
|
12
|
+
|
13
|
+
|
14
|
+
## Simple Setup
|
15
|
+
|
16
|
+
Add this gem to your `Gemfile`
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'osom-tables'
|
20
|
+
```
|
21
|
+
|
22
|
+
Make a partial called `_table.html.haml` in your resource views
|
23
|
+
|
24
|
+
```haml
|
25
|
+
= osom_table_for @things, any_options do |t|
|
26
|
+
|
27
|
+
= t.head do
|
28
|
+
%th Name
|
29
|
+
%th Size
|
30
|
+
|
31
|
+
= t.body do |thing|
|
32
|
+
%td= thing.name
|
33
|
+
%td= thing.size
|
34
|
+
```
|
35
|
+
|
36
|
+
Put it into your `index.html.haml` file the usual way
|
37
|
+
|
38
|
+
```haml
|
39
|
+
%h1 Things
|
40
|
+
|
41
|
+
= render 'table'
|
42
|
+
```
|
43
|
+
|
44
|
+
Add the following thing into your controller
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class ThingsController < ApplicationController
|
48
|
+
def index
|
49
|
+
@things = Thing.page(params[:page])
|
50
|
+
|
51
|
+
render partial: 'table', layout: false if request.xhr?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
And finally, add the assets to your `application.js` and `application.css` files the usual way
|
57
|
+
|
58
|
+
```js
|
59
|
+
*= require 'osom-tables'
|
60
|
+
```
|
61
|
+
|
62
|
+
And you're good to go!
|
63
|
+
|
64
|
+
|
65
|
+
## Adding Sorting
|
66
|
+
|
67
|
+
OsomTables don't enforce any sort of dealing with the sorting, just use your standard scopes.
|
68
|
+
The osom-tables will just handle the views and the `params[:order]` for you.
|
69
|
+
|
70
|
+
Add the order keys to your `t.head` section like so
|
71
|
+
|
72
|
+
```haml
|
73
|
+
= osom_table_for @things do |t|
|
74
|
+
|
75
|
+
= t.head do
|
76
|
+
%th{order: 'name'} Name
|
77
|
+
%th{order: 'size'} Size
|
78
|
+
|
79
|
+
= t.body do |thing|
|
80
|
+
%td= thing.name
|
81
|
+
%td= thing.size
|
82
|
+
```
|
83
|
+
|
84
|
+
This will handle the `params[:order]` automatically, which you can use in your controllers say like that
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class ThingsController < ApplicationController
|
88
|
+
def index
|
89
|
+
@things = Thing.page(params[:page]).order_by(params[:order])
|
90
|
+
|
91
|
+
render parital: 'table', layout: false if request.xhr?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
And then in your models, for example like that
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class Thing
|
100
|
+
scope :order_by, ->(param) {
|
101
|
+
sort = param.ends_with?('_desc') ? 'DESC' : 'ASC'
|
102
|
+
|
103
|
+
case param.sub('_desc', '')
|
104
|
+
when 'name' then order("name #{sort}")
|
105
|
+
when 'size' then order("size #{sort}")
|
106
|
+
else scopped # fallback
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
And don't forget to enjoy the awesomeness of easily unit-testable code!
|
113
|
+
|
114
|
+
|
115
|
+
## HTML5 Push State
|
116
|
+
|
117
|
+
OsomTables can easily hook you up with the html5 push-state goodness.
|
118
|
+
Yes, it's just like `pjax` (whoever come up with this name) only better
|
119
|
+
coz it renders only what needs to be rendered.
|
120
|
+
|
121
|
+
To switch push state on, just pass the `push: true` option with your table
|
122
|
+
|
123
|
+
```haml
|
124
|
+
= osom_tables_for @things, push: true do |t|
|
125
|
+
...
|
126
|
+
```
|
127
|
+
|
128
|
+
|
129
|
+
## Custom Urls
|
130
|
+
|
131
|
+
By default `osom-tables` will use your current url as the base one. But,
|
132
|
+
in case you would like to reuse the `_table` partial, in different locations,
|
133
|
+
you do so, but specifying the `url: smth_path` option with your tables
|
134
|
+
|
135
|
+
```haml
|
136
|
+
= osom_tables_for @things, url: other_things_path do |t|
|
137
|
+
...
|
138
|
+
```
|
139
|
+
|
140
|
+
## License & Copyright
|
141
|
+
|
142
|
+
All code in this repository is released under the terms of the MIT license
|
143
|
+
|
144
|
+
Copyright (C) 2013 Nikolay Nemshilov
|
145
|
+
|
146
|
+
|
147
|
+
|
data/lib/osom-tables.rb
ADDED
data/lib/osom_tables.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module OsomTables::Helper
|
2
|
+
|
3
|
+
def osom_table_for(items, options={}, &block)
|
4
|
+
push = options[:push] == true and options.delete(:push)
|
5
|
+
url = options[:url] || request.fullpath and options.delete(:url)
|
6
|
+
search = options[:search] == true and options.delete(:search)
|
7
|
+
paginate = options[:paginate] || {} and options.delete(:paginate)
|
8
|
+
url = url.gsub(/(\?|&)osom_tables_cache_killa=[^&]*?/, '')
|
9
|
+
|
10
|
+
options[:data] ||= {}
|
11
|
+
options[:data][:url] = url
|
12
|
+
options[:data][:push] = true if push
|
13
|
+
|
14
|
+
content_tag :div, class: 'osom-table' do
|
15
|
+
osom_tables_search(url, search) +
|
16
|
+
|
17
|
+
content_tag(:table, options) {
|
18
|
+
content_tag(:caption, image_tag('osom-tables-spinner.gif', alt: nil), class: 'locker') +
|
19
|
+
capture(Table.new(self, items), &block)
|
20
|
+
} +
|
21
|
+
|
22
|
+
osom_tables_pagination(items, url, paginate)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def osom_tables_search(url, search)
|
27
|
+
''.html_safe if ! search
|
28
|
+
end
|
29
|
+
|
30
|
+
def osom_tables_pagination(items, url, options)
|
31
|
+
if respond_to?(:paginate) # kaminari
|
32
|
+
options[:params] = Rails.application.routes.recognize_path(url, method: :get).merge(options[:params] || {})
|
33
|
+
paginate(items, options)
|
34
|
+
elsif respond_to?(:will_paginate)
|
35
|
+
will_paginate items, options
|
36
|
+
else
|
37
|
+
''.html_safe
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# The thing that we yield into the block
|
43
|
+
#
|
44
|
+
class Table
|
45
|
+
def initialize(context, items)
|
46
|
+
@context = context
|
47
|
+
@items = items
|
48
|
+
end
|
49
|
+
|
50
|
+
def head(&block)
|
51
|
+
head_row = @context.content_tag :tr, &block
|
52
|
+
|
53
|
+
while m = head_row.match(/<th(.*?) (order=("|')(.+?)\3)(.*?)>/)
|
54
|
+
m = m.to_a
|
55
|
+
key = m[4]
|
56
|
+
css = 'sortable'
|
57
|
+
css << ' asc' if @context.params[:order] == key
|
58
|
+
css << ' desc' if @context.params[:order] == key + '_desc'
|
59
|
+
|
60
|
+
[1,5].each do |i|
|
61
|
+
if mc = m[i].match(/ class=("|')(.+)\1/)
|
62
|
+
m[i] = m[i].gsub(mc[0], '')
|
63
|
+
css = "#{mc[2]} #{css}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
head_row.gsub! m[0], "<th#{m[1]} class='#{css}' data-#{m[2]}#{m[5]}>"
|
68
|
+
end
|
69
|
+
|
70
|
+
@context.content_tag :thead, head_row.html_safe
|
71
|
+
end
|
72
|
+
|
73
|
+
def body(&block)
|
74
|
+
@context.content_tag :tbody do
|
75
|
+
@items.map do |item|
|
76
|
+
if defined?(ActiveRecord) && item.is_a?(ActiveRecord::Base)
|
77
|
+
@context.content_tag_for(:tr, item){ yield(item) }
|
78
|
+
else
|
79
|
+
@context.content_tag(:tr){ yield(item) }
|
80
|
+
end
|
81
|
+
end.join("\n").html_safe
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def foot(&block)
|
86
|
+
@context.content_tag :tfoot do
|
87
|
+
@context.content_tag :tr, &block
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class OsomTables::Railtie < Rails::Railtie
|
2
|
+
initializer "osom_tables.view_helpers" do
|
3
|
+
ActionView::Base.send :include, OsomTables::Helper
|
4
|
+
end
|
5
|
+
|
6
|
+
initializer "osom_tables.configure_rails_initialization" do
|
7
|
+
ActionController::Base.instance_eval do
|
8
|
+
before_filter do
|
9
|
+
params.delete(:osom_tables_cache_killa)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class OsomTables::Engine < Rails::Engine
|
16
|
+
end
|
Binary file
|
@@ -0,0 +1,104 @@
|
|
1
|
+
/**
|
2
|
+
* The OsomTables scriptery
|
3
|
+
*
|
4
|
+
* Copyright (C) 2013 Nikolay Nemshilov
|
5
|
+
*/
|
6
|
+
(function($) {
|
7
|
+
|
8
|
+
if (!$) { return console.log("No jQuery? Osom!"); }
|
9
|
+
|
10
|
+
$(document).on('click', '.osom-table .pagination a', function(e) {
|
11
|
+
e.preventDefault();
|
12
|
+
load_table($(this).closest('.osom-table'), this.getAttribute('href'));
|
13
|
+
});
|
14
|
+
|
15
|
+
$(document).on('click', '.osom-table th[data-order]', function(e) {
|
16
|
+
var order = $(this).data('order'), asc = $(this).hasClass('asc');
|
17
|
+
|
18
|
+
load_table($(this).closest('.osom-table'), build_url(
|
19
|
+
$(this).closest('table').data('url'), {
|
20
|
+
order: order + (asc ? '_desc' : ''), page: 1
|
21
|
+
}
|
22
|
+
));
|
23
|
+
});
|
24
|
+
|
25
|
+
$(window).on('popstate', function(e) {
|
26
|
+
var state = e.originalEvent.state;
|
27
|
+
if (state && state.url) {
|
28
|
+
if (current_table && current_table.find('table').data('push')) {
|
29
|
+
load_table(current_table, state.url, true);
|
30
|
+
} else {
|
31
|
+
document.location.href = state.url;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
});
|
35
|
+
|
36
|
+
var current_table = null;
|
37
|
+
|
38
|
+
function load_table(container, url, no_push) {
|
39
|
+
current_table = container.addClass('loading');
|
40
|
+
actual_table = container.find('table');
|
41
|
+
|
42
|
+
actual_table.trigger('osom-table:request');
|
43
|
+
|
44
|
+
if (history.pushState && !no_push && actual_table.data('push')) {
|
45
|
+
history.pushState({url: url}, 'osom-table', url);
|
46
|
+
url = build_url(url, {osom_tables_cache_killa: true});
|
47
|
+
}
|
48
|
+
|
49
|
+
$.ajax(url, {
|
50
|
+
success: function(new_content) {
|
51
|
+
container.html(new_content);
|
52
|
+
},
|
53
|
+
complete: function() {
|
54
|
+
container.removeClass('loading');
|
55
|
+
actual_table.trigger('osom-table:loaded');
|
56
|
+
}
|
57
|
+
});
|
58
|
+
};
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Rebuilds the url with the extra prams
|
62
|
+
*/
|
63
|
+
function build_url(url, params) {
|
64
|
+
var path, args; path = parse_url(url);
|
65
|
+
args = path[1]; path = path[0];
|
66
|
+
|
67
|
+
for (var key in params) {
|
68
|
+
args[key] = params[key];
|
69
|
+
}
|
70
|
+
|
71
|
+
return path + "?" + $.param(args);
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Parsing the arguments out of the url query
|
76
|
+
*/
|
77
|
+
function parse_url(url) {
|
78
|
+
var path, query, args={}, list, key, value;
|
79
|
+
path = url.split("?"); query = path[1]; path = path[0];
|
80
|
+
|
81
|
+
if (query) {
|
82
|
+
for (var i=0, list = query.split('&'); i < list.length; i++) {
|
83
|
+
key = list[i].split('=');
|
84
|
+
value = key[1]; key = key[0];
|
85
|
+
|
86
|
+
key = decodeURIComponent(key);
|
87
|
+
value = decodeURIComponent((value||'').replace(/\+/g, ' '));
|
88
|
+
|
89
|
+
if (key.substr(-2) === "[]") {
|
90
|
+
if (args[key]) {
|
91
|
+
args[key].push(value)
|
92
|
+
} else {
|
93
|
+
args[key] = [value]
|
94
|
+
}
|
95
|
+
} else {
|
96
|
+
args[key] = value
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
return [path, args];
|
102
|
+
}
|
103
|
+
|
104
|
+
})(jQuery);
|
@@ -0,0 +1,88 @@
|
|
1
|
+
/**
|
2
|
+
* Some stock styling for the osom-tables
|
3
|
+
* to provide nice locker/spinner to highlight
|
4
|
+
* the tables loading process
|
5
|
+
*
|
6
|
+
* Copyright (C) 2013 Nikolay Nemshilov
|
7
|
+
*/
|
8
|
+
.osom-table {
|
9
|
+
|
10
|
+
table {
|
11
|
+
position: relative;
|
12
|
+
|
13
|
+
.locker {
|
14
|
+
display: none;
|
15
|
+
position: absolute;
|
16
|
+
z-index: 9999;
|
17
|
+
left: 0;
|
18
|
+
top: 0;
|
19
|
+
width: 100%;
|
20
|
+
height: 100%;
|
21
|
+
background-color: #eee;
|
22
|
+
text-align: center;
|
23
|
+
border-radius: .25em;
|
24
|
+
opacity: .6;
|
25
|
+
|
26
|
+
img {
|
27
|
+
position: relative;
|
28
|
+
top: 40%;
|
29
|
+
height: 25%;
|
30
|
+
width: auto;
|
31
|
+
max-height: 5em;
|
32
|
+
max-width: 5em;
|
33
|
+
padding: 1em;
|
34
|
+
background-color: #fff;
|
35
|
+
border-radius: 1em;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
thead th.sortable {
|
40
|
+
cursor: pointer;
|
41
|
+
transition: background-color .25s ease-in-out;
|
42
|
+
-o-transition: background-color .25s ease-in-out;
|
43
|
+
-ms-transition: background-color .25s ease-in-out;
|
44
|
+
-moz-transition: background-color .25s ease-in-out;
|
45
|
+
-webkit-transition: background-color .25s ease-in-out;
|
46
|
+
|
47
|
+
&:hover, &.asc, &.desc {
|
48
|
+
background-color: #efd;
|
49
|
+
|
50
|
+
&:after {
|
51
|
+
opacity: 1;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
&:after {
|
56
|
+
content: '\25BE';
|
57
|
+
display: block;
|
58
|
+
float: right;
|
59
|
+
opacity: .5;
|
60
|
+
vertical-align: middle;
|
61
|
+
}
|
62
|
+
|
63
|
+
&.desc:after {
|
64
|
+
transform: rotate(180deg);
|
65
|
+
-o-transform: rotate(180deg);
|
66
|
+
-ms-transform: rotate(180deg);
|
67
|
+
-moz-transform: rotate(180deg);
|
68
|
+
-webkit-transform: rotate(180deg);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
&.loading {
|
74
|
+
table {
|
75
|
+
th, td {
|
76
|
+
-webkit-filter: blur(1.5px);
|
77
|
+
-moz-filter: blur(1.5px);
|
78
|
+
-ms-filter: blur(1.5px);
|
79
|
+
-o-filter: blur(1.5px);
|
80
|
+
filter: blur(1.5px);
|
81
|
+
}
|
82
|
+
|
83
|
+
.locker {
|
84
|
+
display: block;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: osom-tables
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nikolay Nemshilov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Fancy ajax tables engine that fits rails infrastructure
|
14
|
+
email: nemshilov@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/osom-tables.rb
|
20
|
+
- lib/osom_tables/helper.rb
|
21
|
+
- lib/osom_tables/railtie.rb
|
22
|
+
- lib/osom_tables.rb
|
23
|
+
- vendor/assets/images/osom-tables-spinner.gif
|
24
|
+
- vendor/assets/javascripts/osom-tables.js
|
25
|
+
- vendor/assets/stylesheets/osom-tables.css.scss
|
26
|
+
- README.md
|
27
|
+
homepage: http://github.com/MadRabbit/osom-tables
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.0.2
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: Fancy ajax tables in true rails style
|
51
|
+
test_files: []
|