magic_grid 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +19 -0
  3. data/Rakefile +44 -0
  4. data/lib/assets/javascripts/magic_grid.js +154 -0
  5. data/lib/locales/en.yml +7 -0
  6. data/lib/magic_grid.rb +7 -0
  7. data/lib/magic_grid/definition.rb +212 -0
  8. data/lib/magic_grid/engine.rb +14 -0
  9. data/lib/magic_grid/helpers.rb +243 -0
  10. data/lib/magic_grid/railtie.rb +9 -0
  11. data/lib/magic_grid/version.rb +3 -0
  12. data/lib/tasks/magic_grid_tasks.rake +4 -0
  13. data/test/dummy/Rakefile +7 -0
  14. data/test/dummy/app/assets/javascripts/application.js +9 -0
  15. data/test/dummy/app/assets/javascripts/posts.js +8 -0
  16. data/test/dummy/app/assets/javascripts/users.js +2 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  18. data/test/dummy/app/assets/stylesheets/posts.css +4 -0
  19. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  20. data/test/dummy/app/assets/stylesheets/users.css +4 -0
  21. data/test/dummy/app/controllers/application_controller.rb +3 -0
  22. data/test/dummy/app/controllers/posts_controller.rb +104 -0
  23. data/test/dummy/app/controllers/users_controller.rb +84 -0
  24. data/test/dummy/app/helpers/application_helper.rb +2 -0
  25. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  26. data/test/dummy/app/helpers/users_helper.rb +2 -0
  27. data/test/dummy/app/models/post.rb +6 -0
  28. data/test/dummy/app/models/user.rb +4 -0
  29. data/test/dummy/app/views/layouts/application.html.erb +19 -0
  30. data/test/dummy/app/views/posts/_form.html.erb +33 -0
  31. data/test/dummy/app/views/posts/by_user.html.erb +18 -0
  32. data/test/dummy/app/views/posts/edit.html.erb +6 -0
  33. data/test/dummy/app/views/posts/index.html.erb +76 -0
  34. data/test/dummy/app/views/posts/new.html.erb +5 -0
  35. data/test/dummy/app/views/posts/show.html.erb +25 -0
  36. data/test/dummy/app/views/users/_form.html.erb +25 -0
  37. data/test/dummy/app/views/users/edit.html.erb +6 -0
  38. data/test/dummy/app/views/users/index.html.erb +42 -0
  39. data/test/dummy/app/views/users/new.html.erb +5 -0
  40. data/test/dummy/app/views/users/show.html.erb +15 -0
  41. data/test/dummy/config.ru +4 -0
  42. data/test/dummy/config/application.rb +59 -0
  43. data/test/dummy/config/boot.rb +10 -0
  44. data/test/dummy/config/database.yml +25 -0
  45. data/test/dummy/config/environment.rb +5 -0
  46. data/test/dummy/config/environments/development.rb +40 -0
  47. data/test/dummy/config/environments/production.rb +67 -0
  48. data/test/dummy/config/environments/test.rb +37 -0
  49. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test/dummy/config/initializers/inflections.rb +15 -0
  51. data/test/dummy/config/initializers/mime_types.rb +5 -0
  52. data/test/dummy/config/initializers/secret_token.rb +7 -0
  53. data/test/dummy/config/initializers/session_store.rb +8 -0
  54. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  55. data/test/dummy/config/locales/en.yml +5 -0
  56. data/test/dummy/config/routes.rb +68 -0
  57. data/test/dummy/db/development.sqlite3 +0 -0
  58. data/test/dummy/db/migrate/20111025191809_create_users.rb +10 -0
  59. data/test/dummy/db/migrate/20111025195229_create_posts.rb +13 -0
  60. data/test/dummy/db/schema.rb +34 -0
  61. data/test/dummy/db/test.sqlite3 +0 -0
  62. data/test/dummy/log/development.log +49565 -0
  63. data/test/dummy/log/passenger.3000.log +362 -0
  64. data/test/dummy/log/test.log +77 -0
  65. data/test/dummy/public/404.html +26 -0
  66. data/test/dummy/public/422.html +26 -0
  67. data/test/dummy/public/500.html +26 -0
  68. data/test/dummy/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  69. data/test/dummy/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  70. data/test/dummy/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  71. data/test/dummy/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  72. data/test/dummy/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  73. data/test/dummy/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  74. data/test/dummy/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  75. data/test/dummy/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  76. data/test/dummy/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  77. data/test/dummy/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  78. data/test/dummy/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  79. data/test/dummy/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  80. data/test/dummy/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  81. data/test/dummy/public/css/smoothness/jquery-ui-1.8.18.custom.css +565 -0
  82. data/test/dummy/public/favicon.ico +0 -0
  83. data/test/dummy/script/rails +6 -0
  84. data/test/dummy/test/fixtures/posts.yml +23 -0
  85. data/test/dummy/test/fixtures/users.yml +15 -0
  86. data/test/dummy/test/functional/posts_controller_test.rb +49 -0
  87. data/test/dummy/test/functional/users_controller_test.rb +50 -0
  88. data/test/dummy/test/integration/spider_test.rb +27 -0
  89. data/test/dummy/test/unit/helpers/posts_helper_test.rb +4 -0
  90. data/test/dummy/test/unit/helpers/users_helper_test.rb +4 -0
  91. data/test/dummy/test/unit/post_test.rb +7 -0
  92. data/test/dummy/test/unit/user_test.rb +7 -0
  93. data/test/magic_grid_test.rb +11 -0
  94. data/test/test_helper.rb +17 -0
  95. metadata +333 -0
@@ -0,0 +1,14 @@
1
+ module MagicGrid
2
+ class Engine < ::Rails::Engine
3
+ # Once in production, on every page view in development
4
+ config.to_prepare do |app|
5
+ # no caching based on path like require does
6
+ load 'magic_grid/helpers.rb'
7
+ end
8
+
9
+ initializer "magic_grid" do |app|
10
+ # Provide some fallback translations that users can override
11
+ app.config.i18n.load_path += Dir.glob(File.expand_path('../../locales/*.{rb,yml}', __FILE__))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,243 @@
1
+ require 'magic_grid/definition'
2
+ require 'will_paginate/array'
3
+
4
+ module MagicGrid
5
+ module Helpers
6
+ def normalize_magic(collection, columns = [], options = {})
7
+ if collection.is_a? MagicGrid::Definition
8
+ collection
9
+ elsif columns.is_a? MagicGrid::Definition
10
+ columns
11
+ elsif options.is_a? MagicGrid::Definition
12
+ options
13
+ else
14
+ MagicGrid::Definition.new(columns, collection, controller, options)
15
+ end
16
+ end
17
+
18
+ def magic_collection(collection, cols, opts = {})
19
+ normalize_magic(collection, cols, opts).collection
20
+ end
21
+
22
+ def magic_grid(collection = nil, cols = nil, opts = {}, &block)
23
+ grid = normalize_magic(collection, cols, opts)
24
+ base_params = grid.base_params
25
+ data = {
26
+ :searcher => grid.options[:searcher],
27
+ :current => url_for,
28
+ :live_search => grid.options[:live_search],
29
+ :listeners => (grid.options[:listeners] unless grid.options[:listeners].empty?),
30
+ :remote => grid.options[:remote],
31
+ :default_ajax_handler => grid.options[:default_ajax_handler],
32
+ :params => base_params,
33
+ }
34
+ classes = ['magic_grid'] << grid.options[:class]
35
+ content_tag('table',
36
+ :class => classes.join(' '),
37
+ :id => grid.magic_id,
38
+ :data => data.select {|_,v| v }
39
+ ) do
40
+ table = content_tag('thead', :data => {:params => base_params}
41
+ ) do
42
+ thead = ''.html_safe
43
+ has_spinner = false
44
+ spinner = tag('span',
45
+ :id => (grid.magic_id.to_s + "_spinner"),
46
+ :class => "magic_grid_spinner"
47
+ )
48
+ if grid.options[:needs_searcher]
49
+ thead << content_tag('tr') do
50
+ content_tag('td', :class => 'searcher full-width ui-widget-header',
51
+ :colspan => grid.columns.count) do
52
+ searcher_data = {
53
+ :min_length => grid.options[:min_search_length],
54
+ :current => grid.options[:current_search] || "",
55
+ }
56
+ searcher = label_tag(grid.options[:searcher].to_sym,
57
+ grid.options[:searcher_label])
58
+ searcher << search_field_tag(grid.options[:searcher].to_sym,
59
+ grid.param(:q),
60
+ :placeholder => grid.options[:searcher_tooltip],
61
+ :size => grid.options[:searcher_size],
62
+ :data => searcher_data,
63
+ :form => "a form that doesn't exist")
64
+ if grid.options[:search_button]
65
+ searcher << button_tag(grid.options[:searcher_button],
66
+ :class => 'magic-grid-search-button')
67
+ end
68
+ unless has_spinner
69
+ has_spinner = true
70
+ searcher << spinner
71
+ end
72
+ searcher
73
+ end
74
+ end
75
+ end
76
+ if grid.options[:per_page] and grid.options[:top_pager]
77
+ thead << content_tag('tr') do
78
+ content_tag('td', :class => 'full-width ui-widget-header',
79
+ :colspan => grid.columns.count) do
80
+ pager = will_paginate(grid.collection,
81
+ :param_name => grid.param_key(:page),
82
+ :params => base_params
83
+ )
84
+ unless has_spinner
85
+ has_spinner = true
86
+ pager << spinner
87
+ end
88
+ pager
89
+ end
90
+ end
91
+ end
92
+ if thead.empty? and not grid.options[:empty_header]
93
+ thead = content_tag 'tr' do
94
+ content_tag('td', :class => 'full-width ui-widget-header',
95
+ :colspan => grid.columns.count) do
96
+ unless has_spinner
97
+ has_spnner = true
98
+ spinner
99
+ end
100
+ end
101
+ end
102
+ end
103
+ thead << magic_headers(grid)
104
+ end
105
+ table << content_tag('tbody', :class => "ui-widget-content") do
106
+ magic_rows(grid, &block)
107
+ end
108
+ table << content_tag('tfoot') do
109
+ tfoot = ''.html_safe
110
+ if grid.options[:per_page] and grid.options[:bottom_pager]
111
+ tfoot << content_tag('tr') do
112
+ content_tag('td', :class => 'full-width ui-widget-header',
113
+ :colspan => grid.columns.count) do
114
+ will_paginate(grid.collection,
115
+ :param_name => grid.param_key(:page),
116
+ :params => base_params
117
+ )
118
+ end
119
+ end
120
+ end
121
+ if tfoot.empty? and not grid.options[:empty_footer]
122
+ tfoot = content_tag 'tr' do
123
+ content_tag('td', nil, :class => 'full-width ui-widget-header',
124
+ :colspan => grid.columns.count)
125
+ end
126
+ end
127
+ tfoot
128
+ end
129
+ end
130
+ end
131
+
132
+ def magic_headers(cols, collection = nil, opts = {})
133
+ grid = normalize_magic(collection, cols, opts)
134
+ content_tag 'tr' do
135
+ grid.columns.reduce(''.html_safe) do |acc, col|
136
+ classes = ['ui-state-default'] << col[:class]
137
+ acc <<
138
+ if col.is_a? String
139
+ content_tag 'th', col.html_safe, :class => classes.join(' ')
140
+ elsif not col.key? :sql
141
+ content_tag 'th', col[:label].html_safe, :class => classes.join(' ')
142
+ else
143
+ sortable_header(grid, col, opts)
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ def magic_rows(cols, collection = nil, &block)
150
+ grid = normalize_magic(collection, cols)
151
+ if_empty = grid.options[:if_empty]
152
+ rows = grid.collection.map do |row|
153
+ if block_given?
154
+ "<!-- block: -->" << capture(row, &block)
155
+ else
156
+ "<!-- magic row: -->" << magic_row(row, grid)
157
+ end
158
+ end
159
+ if rows.empty? and if_empty
160
+ content_tag 'tr' do
161
+ content_tag('td', :colspan => grid.columns.count,
162
+ :class => 'if-empty') do
163
+ if if_empty.respond_to? :call
164
+ if_empty.call(grid).to_s
165
+ else
166
+ if_empty
167
+ end
168
+ end
169
+ end
170
+ else
171
+ rows.join.html_safe
172
+ end
173
+ end
174
+
175
+ def magic_row(record, cols, collection = nil)
176
+ grid = normalize_magic(collection, cols)
177
+ content_tag 'tr', :class => cycle('odd', 'even') do
178
+ grid.columns.reduce(''.html_safe) do |acc, c|
179
+ acc << content_tag('td', :class => c[:class].try(:join, ' ')) do
180
+ method = c[:to_s] || c[:col]
181
+ if method.respond_to? :call
182
+ method.call(record)
183
+ elsif record.respond_to? method
184
+ record.send(method)
185
+ end.to_s
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ def reverse_order(order)
192
+ order.to_i == 0 ? 1 : 0
193
+ end
194
+
195
+ def order_icon(order = -1)
196
+ content_tag 'span', '', :class => "ui-icon #{order_icon_class(order)}"
197
+ end
198
+
199
+ def order_icon_class(order = -1)
200
+ case order.to_i
201
+ when 0 then 'ui-icon-triangle-1-n'
202
+ when 1 then 'ui-icon-triangle-1-s'
203
+ else 'ui-icon-carat-2-n-s'
204
+ end
205
+ end
206
+
207
+ def order_class(order = -1)
208
+ case order.to_i
209
+ when 0 then 'sort-asc'
210
+ when 1 then 'sort-desc'
211
+ else 'sort-none'
212
+ end
213
+ end
214
+
215
+ def sortable_header(grid, col, opts = {})
216
+ id = col[:id]
217
+ label = col[:label] || id.titleize
218
+ default_sort_order = opts.fetch(:default_order, grid.order(grid.default_order))
219
+ my_params = grid.base_params.merge({
220
+ grid.param_key(:col) => id,
221
+ })
222
+ my_params = HashWithIndifferentAccess.new(my_params)
223
+ order = nil
224
+ classes = ['sorter ui-state-default'] << col[:class]
225
+ current = id.to_s == grid.current_sort_col.to_s
226
+ if current
227
+ order = grid.current_order
228
+ classes << "sort-current" << order_class(order)
229
+ my_params[grid.param_key(:order)] = reverse_order(order)
230
+ label << order_icon(order)
231
+ else
232
+ my_params.delete grid.param_key(:order) if my_params[grid.param_key(:order)]
233
+ label << order_icon()
234
+ end
235
+ my_params.delete(grid.param_key(:order)) if my_params[grid.param_key(:order)].to_i == default_sort_order.to_i
236
+ content_tag 'th', :class => classes.join(' ') do
237
+ link_to label.html_safe, my_params, :remote => grid.options[:remote]
238
+ end
239
+ end
240
+
241
+ ::ActionView::Base.send :include, self
242
+ end
243
+ end
@@ -0,0 +1,9 @@
1
+ module MagicGrid
2
+ class Railtie < Rails::Railtie
3
+ # Once in production, on every page view in development
4
+ config.to_prepare do
5
+ # no caching based on path like require does
6
+ load 'magic_grid/helpers.rb'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module MagicGrid
2
+ VERSION = "0.9.2"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :magic_grid do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,9 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require jquery
8
+ //= require jquery_ujs
9
+ //= require_tree .
@@ -0,0 +1,8 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
3
+ $(function () {
4
+ $("#user_id").addClass("ready");
5
+ $(".magic_grid").on("magic_grid:loaded", function () {
6
+ console.log("Loaded a grid: ", this);
7
+ });
8
+ });
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,7 @@
1
+ /*
2
+ * This is a manifest file that'll automatically include all the stylesheets available in this directory
3
+ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4
+ * the top of the compiled file, but it's generally better to create a new file per style scope.
5
+ *= require_self
6
+ *= require_tree .
7
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,104 @@
1
+ class PostsController < ApplicationController
2
+ # GET /posts
3
+ # GET /posts.json
4
+ def index
5
+ @posts = Post.includes(:user)
6
+ @some_array = []
7
+ def @some_array.search(q)
8
+ Rails.logger.debug "Searching for #{q}, really!"
9
+ self
10
+ end
11
+
12
+ if params.key? :user_id and not params[:user_id].empty?
13
+ @title = "Posts by: #{User.find(params[:user_id]).name}"
14
+ @posts = @posts.where(:user_id => params[:user_id])
15
+ end
16
+
17
+ respond_to do |format|
18
+ format.html # index.html.erb
19
+ format.json { render json: @posts }
20
+ end
21
+ end
22
+
23
+ # GET /posts/by-user/1
24
+ # GET /posts/by-user/1.json
25
+ def by_user
26
+ @title = "Posts by: #{User.find(params[:user_id]).name}"
27
+ @posts = Post.includes(:user).where(:user_id => params[:user_id])
28
+ respond_to do |format|
29
+ format.html # by_user.html.erb
30
+ format.json { render json: @posts }
31
+ end
32
+ end
33
+
34
+ # GET /posts/1
35
+ # GET /posts/1.json
36
+ def show
37
+ @post = Post.find(params[:id])
38
+
39
+ respond_to do |format|
40
+ format.html # show.html.erb
41
+ format.json { render json: @post }
42
+ end
43
+ end
44
+
45
+ # GET /posts/new
46
+ # GET /posts/new.json
47
+ def new
48
+ @post = Post.new
49
+
50
+ respond_to do |format|
51
+ format.html # new.html.erb
52
+ format.json { render json: @post }
53
+ end
54
+ end
55
+
56
+ # GET /posts/1/edit
57
+ def edit
58
+ @post = Post.find(params[:id])
59
+ end
60
+
61
+ # POST /posts
62
+ # POST /posts.json
63
+ def create
64
+ @post = Post.new(params[:post])
65
+
66
+ respond_to do |format|
67
+ if @post.save
68
+ format.html { redirect_to @post, notice: 'Post was successfully created.' }
69
+ format.json { render json: @post, status: :created, location: @post }
70
+ else
71
+ format.html { render action: "new" }
72
+ format.json { render json: @post.errors, status: :unprocessable_entity }
73
+ end
74
+ end
75
+ end
76
+
77
+ # PUT /posts/1
78
+ # PUT /posts/1.json
79
+ def update
80
+ @post = Post.find(params[:id])
81
+
82
+ respond_to do |format|
83
+ if @post.update_attributes(params[:post])
84
+ format.html { redirect_to @post, notice: 'Post was successfully updated.' }
85
+ format.json { head :ok }
86
+ else
87
+ format.html { render action: "edit" }
88
+ format.json { render json: @post.errors, status: :unprocessable_entity }
89
+ end
90
+ end
91
+ end
92
+
93
+ # DELETE /posts/1
94
+ # DELETE /posts/1.json
95
+ def destroy
96
+ @post = Post.find(params[:id])
97
+ @post.destroy
98
+
99
+ respond_to do |format|
100
+ format.html { redirect_to posts_url }
101
+ format.json { head :ok }
102
+ end
103
+ end
104
+ end