fancygrid 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/CHANGELOG +9 -2
  2. data/Gemfile +6 -9
  3. data/Gemfile.lock +88 -103
  4. data/README.md +226 -0
  5. data/ROADMAP +0 -1
  6. data/Rakefile +2 -2
  7. data/VERSION +1 -1
  8. data/app/views/fancygrid/controls.html.haml +34 -0
  9. data/app/views/fancygrid/fancygrid.html.haml +18 -0
  10. data/app/views/fancygrid/search.html.haml +24 -0
  11. data/app/views/fancygrid/sort.html.haml +8 -0
  12. data/app/views/fancygrid/table.html.haml +25 -0
  13. data/config/locales/fancygrid.de.yml +17 -19
  14. data/config/locales/fancygrid.en.yml +14 -17
  15. data/fancygrid.gemspec +48 -88
  16. data/lib/assets/javascripts/fancygrid.js +425 -0
  17. data/lib/assets/javascripts/fancygrid.min.js +15 -0
  18. data/lib/assets/stylesheets/fancygrid.css +177 -0
  19. data/lib/fancygrid.rb +63 -44
  20. data/lib/fancygrid/column.rb +165 -0
  21. data/lib/fancygrid/controller/helper.rb +46 -0
  22. data/lib/fancygrid/grid.rb +171 -317
  23. data/lib/fancygrid/node.rb +85 -490
  24. data/lib/fancygrid/object_wrapper.rb +24 -0
  25. data/lib/fancygrid/orm/active_record.rb +39 -0
  26. data/lib/fancygrid/orm/sql_generator.rb +127 -0
  27. data/lib/fancygrid/view/helper.rb +44 -0
  28. data/lib/fancygrid/view_state.rb +161 -0
  29. data/spec/column_spec.rb +29 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +48 -0
  31. data/spec/dummy/app/views/application/index.html.haml +11 -0
  32. data/spec/dummy/app/views/layouts/application.html.erb +1 -1
  33. data/spec/dummy/config/application.rb +1 -1
  34. data/spec/dummy/config/environments/development.rb +2 -2
  35. data/spec/dummy/config/environments/test.rb +2 -2
  36. data/spec/dummy/config/routes.rb +3 -2
  37. data/spec/dummy/db/development.sqlite3 +0 -0
  38. data/spec/dummy/db/schema.rb +26 -0
  39. data/spec/dummy/public/javascripts/jquery-1.4.2.js +6240 -0
  40. data/spec/dummy/public/javascripts/jquery-fancygrid.js +425 -0
  41. data/spec/dummy/public/javascripts/jquery-ui.js +41 -0
  42. data/spec/dummy/public/stylesheets/fancygrid.css +183 -0
  43. data/spec/node_spec.rb +79 -301
  44. data/spec/spec_helper.rb +0 -29
  45. data/spec/view_state_spec.rb +91 -0
  46. metadata +124 -137
  47. data/.bundle/config +0 -2
  48. data/README.rdoc +0 -299
  49. data/app/views/fancygrid/_cells.html.haml +0 -13
  50. data/app/views/fancygrid/base/controls.html.haml +0 -40
  51. data/app/views/fancygrid/base/list_frame.html.haml +0 -37
  52. data/app/views/fancygrid/base/search.html.haml +0 -33
  53. data/app/views/fancygrid/base/sort.html.haml +0 -20
  54. data/app/views/fancygrid/base/table_frame.html.haml +0 -45
  55. data/config/initializers/fancygrid.rb +0 -67
  56. data/lib/fancygrid/helper.rb +0 -129
  57. data/lib/fancygrid/query_generator.rb +0 -340
  58. data/lib/fancygrid/view.rb +0 -148
  59. data/lib/generators/install_generator.rb +0 -61
  60. data/lib/generators/views_generator.rb +0 -25
  61. data/lib/version.rb +0 -0
  62. data/public/images/fancygrid/add.png +0 -0
  63. data/public/images/fancygrid/clear.png +0 -0
  64. data/public/images/fancygrid/ddn.png +0 -0
  65. data/public/images/fancygrid/dn.png +0 -0
  66. data/public/images/fancygrid/dots.png +0 -0
  67. data/public/images/fancygrid/loading.gif +0 -0
  68. data/public/images/fancygrid/magnifier.png +0 -0
  69. data/public/images/fancygrid/next.png +0 -0
  70. data/public/images/fancygrid/order.png +0 -0
  71. data/public/images/fancygrid/prev.png +0 -0
  72. data/public/images/fancygrid/reload.png +0 -0
  73. data/public/images/fancygrid/remove.png +0 -0
  74. data/public/images/fancygrid/spacer.gif +0 -0
  75. data/public/images/fancygrid/submit.png +0 -0
  76. data/public/images/fancygrid/th_bg.png +0 -0
  77. data/public/images/fancygrid/up.png +0 -0
  78. data/public/images/fancygrid/uup.png +0 -0
  79. data/public/javascripts/fancygrid.js +0 -477
  80. data/public/javascripts/fancygrid.min.js +0 -17
  81. data/public/stylesheets/fancygrid.css +0 -289
  82. data/public/stylesheets/fancygrid.scss +0 -302
  83. data/spec/dummy/log/development.log +0 -0
  84. data/spec/dummy/log/production.log +0 -0
  85. data/spec/dummy/log/server.log +0 -0
  86. data/spec/dummy/log/test.log +0 -1026
  87. data/spec/dummy/public/javascripts/application.js +0 -2
  88. data/spec/dummy/public/javascripts/controls.js +0 -965
  89. data/spec/dummy/public/javascripts/dragdrop.js +0 -974
  90. data/spec/dummy/public/javascripts/effects.js +0 -1123
  91. data/spec/dummy/public/javascripts/prototype.js +0 -6001
  92. data/spec/dummy/public/javascripts/rails.js +0 -175
  93. data/spec/grid_spec.rb +0 -15
  94. data/spec/integration/navigation_spec.rb +0 -9
  95. data/spec/query_generator_spec.rb +0 -358
@@ -0,0 +1,24 @@
1
+ module Fancygrid
2
+ class ObjectWrapper
3
+
4
+ # Initializes the object wrapper
5
+ #
6
+ def initialize obj
7
+ @wrapped = obj
8
+ end
9
+
10
+ # Gets the wrapped object
11
+ #
12
+ def object
13
+ @wrapped
14
+ end
15
+
16
+ # Sends the missing method to the wrapped object
17
+ # and stores the result as the new wrapped object
18
+ #
19
+ def method_missing(method, *args, &block)
20
+ @wrapped = @wrapped.send(method, *args)
21
+ return self
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,39 @@
1
+ module Fancygrid
2
+ module Orm
3
+ class ActiveRecord
4
+ include Fancygrid::Orm::SqlGenerator
5
+
6
+ def execute resource_class, &block
7
+ query = resource_class.where({})
8
+
9
+ if self.query_options[:select].present?
10
+ query = query.select(self.query_options[:select])
11
+ end
12
+
13
+ if self.query_options[:conditions].present?
14
+ query = query.where(self.query_options[:conditions])
15
+ end
16
+
17
+ if self.query_options[:order].present?
18
+ query = query.order(self.query_options[:order])
19
+ end
20
+
21
+ if block_given?
22
+ wrapper = Fancygrid::ObjectWrapper.new(query)
23
+ yield wrapper
24
+ query = wrapper.object
25
+ end
26
+
27
+ count = query.count
28
+
29
+ if !self.query_options[:offset].nil? && !self.query_options[:limit].nil?
30
+ query = query.offset(self.query_options[:offset])
31
+ query = query.limit(self.query_options[:limit])
32
+ end
33
+
34
+ return query.to_a, count
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,127 @@
1
+ module Fancygrid
2
+ module Orm
3
+ module SqlGenerator#:nodoc:
4
+
5
+ OPERATOR_NAMES = [
6
+ :equal, :not_equal, :less, :less_equal, :greater, :greater_equal, :starts_with, :ends_with,
7
+ :like, :is_null, :is_not_null, :is_true, :is_not_true, :is_false, :is_not_false, :in, :not_in
8
+ ]
9
+
10
+ attr_accessor :query_options
11
+
12
+ def initialize(options)
13
+
14
+ self.query_options = {}
15
+
16
+ if grid = options[:grid]
17
+ self.query_options[:order] = grid.view_state.sql_order
18
+ end
19
+
20
+ if select = options[:select]
21
+ self.query_options[:select] = select
22
+ end
23
+
24
+ if pagination = options[:pagination]
25
+ self.query_options[:limit] = pagination[:per_page].to_i
26
+ self.query_options[:offset] = (pagination[:page].to_i - 1) * pagination[:per_page].to_i
27
+ end
28
+
29
+ if conditions = self.build_conditions(options[:operator], options[:conditions])
30
+ self.query_options[:conditions] = conditions
31
+ end
32
+ end
33
+
34
+ def execute resource_class
35
+ raise "called execute on abstract class"
36
+ end
37
+
38
+ protected
39
+
40
+ def build_conditions(operator, search_conditions)
41
+ return nil if Array(search_conditions).empty?
42
+
43
+ operator = logical_operator(operator)
44
+ conditions = []
45
+ arguments = []
46
+
47
+ Array(search_conditions).each do |options|
48
+ sql, value = comparison_operator(options[:identifier], options[:operator], options[:value])
49
+ conditions << sql
50
+ arguments << value unless value.nil?
51
+ end
52
+
53
+ return [conditions.join(operator)] + arguments
54
+ end
55
+
56
+ def comparison_operator(column, operator, value)
57
+ operator = case operator.to_s
58
+ when "equal"
59
+ "="
60
+ when "not_equal"
61
+ "!="
62
+ when "less"
63
+ "<"
64
+ when "less_equal"
65
+ "<="
66
+ when "greater"
67
+ ">"
68
+ when "greater_equal"
69
+ ">="
70
+ when "starts_with"
71
+ value = "#{value.to_param}%"
72
+ "LIKE"
73
+ when "ends_with"
74
+ value = "%#{value.to_param}"
75
+ "LIKE"
76
+ when "like"
77
+ value = "%#{value.to_param}%"
78
+ "LIKE"
79
+ when "is_null"
80
+ value = nil
81
+ "IS NULL"
82
+ when "is_not_null"
83
+ value = nil
84
+ "IS NOT NULL"
85
+ when "is_true"
86
+ value = nil
87
+ "IS TRUE"
88
+ when "is_not_true"
89
+ value = nil
90
+ "IS NOT TRUE"
91
+ when "is_false"
92
+ value = nil
93
+ "IS FALSE"
94
+ when "is_not_false"
95
+ value = nil
96
+ "IS NOT FALSE"
97
+ when "in"
98
+ value = value.split(",")
99
+ "IN"
100
+ when "not_in"
101
+ value = value.split(",")
102
+ "NOT IN"
103
+ else
104
+ "="
105
+ end
106
+
107
+ if value.nil?
108
+ return "( #{column} #{operator} )", value
109
+ else
110
+ return "( #{column} #{operator} (?) )", value
111
+ end
112
+
113
+ end
114
+
115
+ def logical_operator(name)
116
+ case name.to_s
117
+ when "all", "and"
118
+ " AND "
119
+ else
120
+ " OR "
121
+ end
122
+ end
123
+
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,44 @@
1
+ module Fancygrid
2
+ module View
3
+ module Helper
4
+ # Renders an existing fancygrid for the given name. A rendering block
5
+ # may be passed to format column values.
6
+ #
7
+ def fancygrid(name, options={}, &block)#:yields: column, record, value
8
+ instance = @fancygrid_collection && @fancygrid_collection[name]
9
+ raise "Unknown fancygrid name: '#{name}'" if instance.nil?
10
+ render :template => instance.options[:base_template], :locals => { :fancygrid => instance, :format_block => block }
11
+ end
12
+
13
+ # Fetches a value from given record and applies a formatter on it.
14
+ #
15
+ def render_fancygrid_cell(record, column, &format_block)
16
+ value = column.fetch_value_and_format(record)
17
+ format_fancygrid_value(record, column, value, &format_block)
18
+ end
19
+
20
+ # Renders the given <tt>record</tt>, <tt>column</tt> and <tt>value</tt>
21
+ # with the formatter block.
22
+ #
23
+ def format_fancygrid_value(record, column, value=nil, &format_block)
24
+ if block_given?
25
+ if defined?(Haml::Helpers) && is_haml?
26
+ capture_haml(column, record, value, &format_block)
27
+ else
28
+ capture(column, record, value, &format_block)
29
+ end
30
+ #elsif !column.root.cell_template.nil?
31
+ # render( :template => column.root.cell_template, :inline => true, :locals => {
32
+ # :grid => column.root,
33
+ # :record => record,
34
+ # :column => column,
35
+ # :value => value
36
+ # })
37
+ else
38
+ value
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,161 @@
1
+ module Fancygrid#:nodoc:
2
+
3
+ #{
4
+ # :columns => [
5
+ # { :identifier => <string>, :visible => <bool>, :position => <number> }
6
+ # ]
7
+ # :conditions => [
8
+ # { :identifier => <string>, :operator => <string>, :value => <string> }
9
+ # ],
10
+ # :operator => ["all"|"any"],
11
+ # :order => { :identifier => <string>, :direction => ["asc"|"desc"|""] },
12
+ # :pagination => { :page => <number>, :per_page => <number> }
13
+ #}
14
+ class ViewState
15
+
16
+ attr_accessor :dump
17
+
18
+ def initialize(dump = {})
19
+ raise ArgumentError, "'dump' must be a Hash" unless dump.is_a? Hash
20
+ self.dump = dump.with_indifferent_access
21
+ self.fix_columns
22
+ self.fix_conditions
23
+ self.fix_order
24
+ self.fix_pagination
25
+ end
26
+
27
+ def column_options(node)
28
+ self.dump[:columns].select { |hash|
29
+ node.identifier == hash[:identifier]
30
+ }.first || {}
31
+ end
32
+
33
+ def column_option(node, option, default)
34
+ self.column_options(node).fetch(option, default)
35
+ end
36
+
37
+ def column_conditions(node)
38
+ self.dump[:conditions].select { |hash|
39
+ node.identifier == hash[:identifier]
40
+ }.first || {}
41
+ end
42
+
43
+ def column_condition(node, option, default)
44
+ self.column_conditions(node).fetch(option.to_s, default)
45
+ end
46
+
47
+ def conditions
48
+ self.dump[:conditions]
49
+ end
50
+
51
+ def operator
52
+ self.dump[:operator]
53
+ end
54
+
55
+ def conditions_match_all?
56
+ self.dump.fetch(:conditions_match, :any).to_s == "all"
57
+ end
58
+
59
+ def order
60
+ self.dump.fetch(:order, {})
61
+ end
62
+
63
+ def order_table
64
+ self.order[:identifier].to_s.split(".").first
65
+ end
66
+
67
+ def order_column
68
+ self.order[:identifier].to_s.split(".").last
69
+ end
70
+
71
+ def order_direction
72
+ self.order[:direction]
73
+ end
74
+
75
+ def column_order(node)
76
+ if node.identifier.to_s == self.order[:identifier].to_s
77
+ self.order_direction
78
+ end
79
+ end
80
+
81
+ def ordered?
82
+ !(order_table.blank? || order_column.blank? || order_direction.blank?)
83
+ end
84
+
85
+ def sql_order
86
+ return nil unless ordered?
87
+ return "#{order_table}.#{order_column} #{order_direction}"
88
+ end
89
+
90
+ def pagination
91
+ self.dump.fetch(:pagination, {})
92
+ end
93
+
94
+ def pagination_page default=1
95
+ result = self.pagination.fetch(:page, default)
96
+ return default if result <= 0
97
+ return result
98
+ end
99
+
100
+ def pagination_per_page default=20
101
+ result = self.pagination.fetch(:per_page, default)
102
+ return default if result <= 0
103
+ return result
104
+ end
105
+
106
+ def pagination_options(default_page, default_per_page)
107
+ {
108
+ :page => self.pagination_page(default_page).to_i,
109
+ :per_page => self.pagination_per_page(default_per_page).to_i
110
+ }
111
+ end
112
+
113
+ def search_visible
114
+ self.dump.fetch(:search_visible, false)
115
+ end
116
+
117
+ protected
118
+ # converts the columns option into an array of hashes
119
+ #
120
+ def fix_columns
121
+ h = self.dump
122
+ # conditions may be passed as a hash like { "0" => {}, "1" => {}}
123
+ h[:columns] = h[:columns].values if h[:columns].is_a? Hash
124
+ # ensure that columns is an array
125
+ h[:columns] = [] unless h[:columns].is_a? Array
126
+ # filter out invalid entries.
127
+ h[:columns] = h[:columns].select { |entry| entry.is_a?(Hash) }
128
+ end
129
+
130
+ # converts the conditions options in to an array of hashes
131
+ # with at least an :identifier and :operator
132
+ #
133
+ # { :identifier => <string>, :operator => [all|any] }
134
+ def fix_conditions
135
+ h = self.dump
136
+
137
+ # conditions may be passed as a hash like { "0" => {}, "1" => {}}
138
+ h[:conditions] = h[:conditions].values if h[:conditions].is_a? Hash
139
+ # ensure that conditions is an array
140
+ h[:conditions] = [] unless h[:conditions].is_a? Array
141
+ # filter out invalid entries.
142
+ h[:conditions] = h[:conditions].select { |entry| entry.is_a?(Hash) && entry[:identifier].present? && entry[:operator].present? }
143
+ h[:operator] = "all" unless %w(all any).include? h[:operator]
144
+ end
145
+
146
+ def fix_order
147
+ self.dump[:order] = {} unless self.dump[:order].is_a? Hash
148
+ hash = self.dump[:order]
149
+ hash.delete(:identifier)unless hash[:identifier].is_a? String
150
+ hash.delete(:direction) unless %w(asc desc).include? hash[:direction]
151
+ end
152
+
153
+ def fix_pagination
154
+ self.dump[:pagination] = {} unless self.dump[:pagination].is_a? Hash
155
+ hash = self.dump[:pagination]
156
+ hash[:page] = hash[:page].to_i if hash.has_key? :page
157
+ hash[:per_page] = hash[:per_page].to_i if hash.has_key? :per_page
158
+ end
159
+
160
+ end
161
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Fancygrid::Column do
4
+
5
+ class DummyClass
6
+ def self.table_name; "dummy_table"; end;
7
+ end
8
+
9
+ before :each do
10
+ @node = Fancygrid::Node.new(nil, :project, {})
11
+ end
12
+
13
+ it "#identifier should combine table_name and column name" do
14
+ @node.column :description
15
+ @node.children.last.identifier.should == "projects.description"
16
+ end
17
+
18
+ it "#select_name should combine table_name and column name" do
19
+ @node.column :description
20
+ @node.children.last.identifier.should == "projects.description"
21
+ end
22
+
23
+ it "#tag_class should contain table_name and name" do
24
+ @node.column :description
25
+ @node.children.last.tag_class.include?("projects").should be true
26
+ @node.children.last.tag_class.include?("description").should be true
27
+ end
28
+
29
+ end
@@ -1,3 +1,51 @@
1
1
  class ApplicationController < ActionController::Base
2
+
2
3
  protect_from_forgery
4
+
5
+ def index
6
+ #Project.destroy_all
7
+ if Project.count < 10
8
+ 10.times do |i|
9
+ proj = Project.create :title => "Project #{i}"
10
+ 3.times do
11
+ proj.tickets.create!
12
+ end
13
+ end
14
+ end
15
+
16
+ projects_grid = fancygrid_for :projects, :builder => MyGrid, :persist => true do |grid|
17
+ grid.ajax_url = "/index.html"
18
+ grid.paginate = request.format.html?
19
+ grid.select = true
20
+ grid.find do |q|
21
+ q.includes :tickets
22
+ end
23
+ end
24
+
25
+ respond_to do |format|
26
+ format.html { render }
27
+ format.json { render :json => projects_grid.records }
28
+ format.xml { render :xml => projects_grid.dump_records }
29
+ end
30
+ end
31
+ end
32
+
33
+ class MyGrid < Fancygrid::Grid
34
+
35
+ def apply_options(options)
36
+ super
37
+
38
+ self.attributes :id, :title
39
+ self.columns :hash, :object_id
40
+ self.columns_for :tickets do |t|
41
+ t.columns :id
42
+ end
43
+ #self.components -= [:search_bar]
44
+ self.components += [:sort_window]
45
+ #self.ajax_url = "/"
46
+ self.ajax_type = :get
47
+
48
+ self.search_filter "projects.title", [["-- choose --", ""], [:foo, :foo], [:bar, :bar]]
49
+ end
50
+
3
51
  end