fancygrid 1.1.0 → 2.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.
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