osom-tables 1.0.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5fd6cce444e1be672327791d4721d373553335f8
4
+ data.tar.gz: facda0539d1e13e51ae6844b22d93c2cb814e2cb
5
+ SHA512:
6
+ metadata.gz: b4524680c19d243df750a93e986406db7de9edb56b4af6b8e07ab2e6327dbf76620a810f807db89e460a9fdc5a769d6efa5208713455c9e61a4beb8f9aefd9a0
7
+ data.tar.gz: 96141a88e8fe9fe7f22a00ae24587e83bf58efe78d37363fa898184794b8ea38c47a592203ab84507ffee74a18e1ae1c17aac86e0ce1d90e6e978b872dff886e
@@ -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
+
@@ -0,0 +1,6 @@
1
+ #
2
+ # Just a gem hook
3
+ #
4
+ require 'osom_tables'
5
+ require 'osom_tables/helper'
6
+ require 'osom_tables/railtie' if defined?(Rails)
@@ -0,0 +1,3 @@
1
+ module OsomTables
2
+ VERSION = '1.0.0'
3
+ end
@@ -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
@@ -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: []