lolita 3.1.17 → 3.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/VERSION +1 -1
  2. data/app/controllers/lolita/field_data_controller.rb +36 -0
  3. data/app/controllers/lolita/info_controller.rb +12 -1
  4. data/app/controllers/lolita/rest_controller.rb +8 -3
  5. data/app/helpers/lolita_helper.rb +12 -1
  6. data/app/views/components/lolita/configuration/column/_display.html.erb +1 -1
  7. data/app/views/components/lolita/configuration/column/_header.html.erb +1 -1
  8. data/app/views/components/lolita/configuration/column/_sort.html.erb +7 -4
  9. data/app/views/components/lolita/configuration/field/array/_display.html.erb +1 -1
  10. data/app/views/components/lolita/configuration/field/array/autocomplete/_display.html.haml +11 -0
  11. data/app/views/components/lolita/configuration/field/array/checkbox/_display.html.haml +8 -0
  12. data/app/views/components/lolita/configuration/field/array/polymorphic/_display.html.haml +6 -0
  13. data/app/views/components/lolita/configuration/field/array/polymorphic/_options_for_select.html.haml +1 -0
  14. data/app/views/components/lolita/configuration/field/array/select/_display.html.erb +1 -1
  15. data/app/views/components/lolita/configuration/field/string/_display.html.erb +1 -5
  16. data/app/views/components/lolita/configuration/field/string/disabled/_display.html.erb +1 -1
  17. data/app/views/components/lolita/configuration/field/string/text/_display.html.erb +1 -1
  18. data/app/views/components/lolita/configuration/list/_paginator.html.erb +1 -1
  19. data/app/views/components/lolita/configuration/list/_title.html.erb +6 -1
  20. data/app/views/components/lolita/configuration/nested_form/_display.html.erb +8 -6
  21. data/app/views/components/lolita/configuration/search/_display.html.haml +2 -0
  22. data/app/views/components/lolita/navigation/_tree.html.erb +18 -25
  23. data/app/views/components/lolita/shared/_header.html.erb +1 -1
  24. data/app/views/components/lolita/shared/_right_sidebar.html.erb +1 -6
  25. data/app/views/components/lolita/shared/_save_button.html.erb +6 -0
  26. data/config/locales/en.yml +9 -1
  27. data/config/locales/lv.yml +6 -5
  28. data/config/routes.rb +3 -1
  29. data/lib/lolita.rb +52 -35
  30. data/lib/lolita/adapter/abstract_adapter.rb +5 -5
  31. data/lib/lolita/adapter/active_record.rb +190 -84
  32. data/lib/lolita/adapter/field_helper.rb +19 -0
  33. data/lib/lolita/adapter/mongoid.rb +217 -64
  34. data/lib/lolita/builder.rb +1 -1
  35. data/lib/lolita/configuration/base.rb +17 -4
  36. data/lib/lolita/configuration/column.rb +47 -28
  37. data/lib/lolita/configuration/columns.rb +1 -1
  38. data/lib/lolita/configuration/factory/field.rb +45 -0
  39. data/lib/lolita/configuration/factory/tab.rb +18 -0
  40. data/lib/lolita/configuration/field.rb +30 -115
  41. data/lib/lolita/configuration/field/array.rb +126 -41
  42. data/lib/lolita/configuration/field/big_decimal.rb +2 -2
  43. data/lib/lolita/configuration/field/boolean.rb +2 -2
  44. data/lib/lolita/configuration/field/date.rb +2 -2
  45. data/lib/lolita/configuration/field/date_time.rb +2 -2
  46. data/lib/lolita/configuration/field/float.rb +9 -0
  47. data/lib/lolita/configuration/field/hash.rb +9 -0
  48. data/lib/lolita/configuration/field/hidden.rb +2 -2
  49. data/lib/lolita/configuration/field/integer.rb +2 -3
  50. data/lib/lolita/configuration/field/range.rb +9 -0
  51. data/lib/lolita/configuration/field/string.rb +5 -2
  52. data/lib/lolita/configuration/field/symbol.rb +9 -0
  53. data/lib/lolita/configuration/field/time.rb +2 -2
  54. data/lib/lolita/configuration/list.rb +41 -8
  55. data/lib/lolita/configuration/nested_form.rb +2 -2
  56. data/lib/lolita/configuration/search.rb +91 -0
  57. data/lib/lolita/configuration/tab.rb +11 -14
  58. data/lib/lolita/configuration/tab/content.rb +1 -2
  59. data/lib/lolita/configuration/tab/default.rb +0 -1
  60. data/lib/lolita/configuration/tabs.rb +17 -11
  61. data/lib/lolita/controller_additions.rb +15 -0
  62. data/lib/lolita/controllers/authorization_helpers.rb +56 -0
  63. data/lib/lolita/controllers/component_helpers.rb +1 -1
  64. data/lib/lolita/controllers/internal_helpers.rb +18 -4
  65. data/lib/lolita/controllers/url_helpers.rb +5 -1
  66. data/lib/lolita/controllers/user_helpers.rb +23 -11
  67. data/lib/lolita/dbi/base.rb +7 -1
  68. data/lib/lolita/hooks.rb +163 -120
  69. data/lib/lolita/lazy_loader.rb +3 -0
  70. data/lib/lolita/mapping.rb +25 -2
  71. data/lib/lolita/modules/rest.rb +1 -1
  72. data/lib/lolita/navigation/branch.rb +52 -1
  73. data/lib/lolita/navigation/tree.rb +10 -0
  74. data/lib/lolita/rails.rb +1 -2
  75. data/lib/lolita/rails/routes.rb +4 -5
  76. data/lib/lolita/search/simple.rb +76 -0
  77. data/lib/lolita/system_configuration/application.rb +7 -1
  78. data/lolita.gemspec +33 -13
  79. data/public/stylesheets/lolita/style.css +21 -0
  80. data/spec/configuration/column_spec.rb +2 -2
  81. data/spec/configuration/columns_spec.rb +1 -1
  82. data/spec/configuration/field_spec.rb +14 -43
  83. data/spec/configuration/list_spec.rb +24 -20
  84. data/spec/configuration/search_spec.rb +44 -0
  85. data/spec/configuration/tab_spec.rb +21 -31
  86. data/spec/configuration/tabs_spec.rb +2 -2
  87. data/spec/dbi/base_spec.rb +3 -9
  88. data/spec/rails_app/app/mongoid/post.rb +4 -0
  89. data/spec/rails_app/config/application.rb +12 -1
  90. data/spec/rails_app/config/environments/development.rb +6 -2
  91. data/spec/rails_app/config/environments/production.rb +5 -1
  92. data/spec/rails_app/config/environments/test.rb +5 -1
  93. data/spec/search/simple_spec.rb +48 -0
  94. data/spec/spec_helper.rb +29 -18
  95. metadata +55 -38
  96. data/spec/configuration/page_spec.rb +0 -20
@@ -80,7 +80,7 @@ module Lolita
80
80
  end
81
81
 
82
82
  def build
83
-
83
+
84
84
  path = if conditions?
85
85
  switch_path do |name,state|
86
86
  if conditions_met?
@@ -15,9 +15,11 @@ module Lolita
15
15
 
16
16
  attr_reader :dbi,:klass
17
17
  @@generators=[:tabs,:list]
18
+
18
19
  class << self
20
+
19
21
  def add_generator(method)
20
- @@generators<<method.to_sym
22
+ @@generators<<method.to_sym
21
23
  end
22
24
  end
23
25
  # When configuration is defined in class than you don't need to worry about
@@ -38,8 +40,9 @@ module Lolita
38
40
  # Person.lolita=Lolita::Configuration::Base.new(Person)
39
41
  # Person.lolita.klass #=> Person
40
42
  def initialize(orm_class,&block)
43
+ @in_callback_mode = false
41
44
  @klass=orm_class
42
- @dbi=Lolita::DBI::Base.new(orm_class)
45
+ @dbi=Lolita::DBI::Base.create(orm_class)
43
46
  block_given? ? self.instance_eval(&block) : self.generate!
44
47
  end
45
48
 
@@ -50,6 +53,10 @@ module Lolita
50
53
  Lolita::LazyLoader.lazy_load(self,:@list,Lolita::Configuration::List,@dbi,&block)
51
54
  end
52
55
 
56
+ def list=(new_list)
57
+ @list = new_list if new_list.is_a?(Lolita::Configuration::List)
58
+ end
59
+
53
60
  # Create collection of Lolita::Configuration::Tab, loading lazy.
54
61
  # See Lolita::Configuration::Tabs for details.
55
62
  def tabs &block
@@ -60,7 +67,7 @@ module Lolita
60
67
  # Tabs should not be defined in lolita block to create onew or more Lolita::Configuration::Tab
61
68
  # See Lolita::Configuration::Tab for details of defination.
62
69
  def tab *args, &block
63
- self.tabs<<Lolita::Configuration::Tab.add(@dbi,*args,&block)
70
+ self.tabs<<Lolita::Configuration::Factory::Tab.add(@dbi,*args,&block)
64
71
  end
65
72
 
66
73
  # Call all supported instance metods to set needed variables and initialize object with them.
@@ -69,7 +76,13 @@ module Lolita
69
76
  self.send(generator)
70
77
  }
71
78
  end
72
-
79
+
80
+ private
81
+
82
+ def after_initialize
83
+ @dbi.klass.run(:after_lolita_loaded, :once => self)
84
+ end
85
+
73
86
  end
74
87
  end
75
88
  end
@@ -12,7 +12,21 @@ module Lolita
12
12
  self.set_attributes(*args)
13
13
  self.instance_eval(&block) if block_given?
14
14
  validate
15
- set_default_values
15
+ end
16
+
17
+ def value(record)
18
+ if self.name.to_s.match(/_id$/) && record.respond_to?(self.name.to_s.gsub(/_id$/,"").to_sym)
19
+ remote_record = record.send(self.name.to_s.gsub(/_id$/,"").to_sym)
20
+ if remote_record.respond_to?(:title)
21
+ remote_record.send(:title)
22
+ elsif remote_record.respond_to?(:name)
23
+ remote_record.send(:name)
24
+ else
25
+ record.send(self.name)
26
+ end
27
+ else
28
+ record.send(self.name)
29
+ end
16
30
  end
17
31
 
18
32
  def title(value=nil)
@@ -24,20 +38,34 @@ module Lolita
24
38
  def sortable?
25
39
  @sortable
26
40
  end
27
-
28
- def currently_sorting?(params)
29
- @sortable && params[:sc].to_s==self.name.to_s
41
+
42
+ def current_sort_state(params)
43
+ @sortable && sort_pairs(params).detect{|pair| pair[0]==self.name.to_s} || []
30
44
  end
31
45
 
32
- def sort_options(params)
33
- direction=if params[:sc].to_s==self.name.to_s
34
- params[:sd].to_s=="asc" ? "desc" : "asc"
46
+ def sort_params params
47
+ if @sortable
48
+ pairs = sort_pairs(params)
49
+ found_pair = false
50
+ pairs.each_with_index{|pair,index|
51
+ if pair[0] == self.name.to_s
52
+ pairs[index][1] = pair[1] == "asc" ? "desc" : "asc"
53
+ found_pair = true
54
+ end
55
+ }
56
+ unless found_pair
57
+ pairs << [self.name.to_s,"asc"]
58
+ end
59
+ (pairs.map{|pair| pair.join(",")}).join("|")
35
60
  else
36
- "desc"
61
+ ""
37
62
  end
38
- {:sc=>self.name,:sd=>direction}
39
63
  end
40
-
64
+
65
+ def sort_pairs params
66
+ (params[:s] || "").split("|").map{|pair| pair.split(",")}
67
+ end
68
+
41
69
  # Define format, for details see Lolita::Support::Formatter and Lolita::Support::Formater::Rails
42
70
  def formatter(value=nil,&block)
43
71
  if block_given?
@@ -61,29 +89,20 @@ module Lolita
61
89
  end
62
90
 
63
91
  def set_attributes(*args)
64
- if !args.empty?
65
- if args[0].is_a?(Hash)
66
- args[0].each{|m,value|
67
- self.send("#{m}=".to_sym,value)
68
- }
69
- elsif args[0].is_a?(Symbol) || args[0].is_a?(String)
70
- self.name=args[0].to_s
71
- if args[1].is_a?(Hash)
72
- args[1].each{|m,value|
73
- self.send("#{m}=".to_sym,value)
74
- }
75
- end
76
- else
77
- raise ArgumentError.new("Lolita::Configuration::Column arguments must be Hash or Symbol or String instead of #{args[0].class}")
92
+ options = args ? args.extract_options! : {}
93
+ if args[0].respond_to?(:field)
94
+ [:name,:type].each do |attr|
95
+ self.send(:"#{attr}=",args[0].send(attr))
78
96
  end
97
+ elsif args[0]
98
+ self.name = args[0]
99
+ end
100
+ options.each do |attr_name,value|
101
+ self.send(:"#{attr_name}=",value)
79
102
  end
80
103
  end
81
104
 
82
105
  private
83
-
84
- def set_default_values
85
- @sort_direction||=:desc
86
- end
87
106
 
88
107
  def validate
89
108
  raise ArgumentError.new("Column must have name.") unless self.name
@@ -28,7 +28,7 @@ module Lolita
28
28
  def generate!
29
29
  @columns.clear
30
30
  @dbi.fields.each_with_index{|field,index|
31
- unless Lolita::Configuration::Helper.tehnical_field?(field,@dbi)
31
+ unless field.technical?
32
32
  @columns << Lolita::Configuration::Column.new(@dbi,field)
33
33
  end
34
34
  }
@@ -0,0 +1,45 @@
1
+ module Lolita
2
+ module Configuration
3
+ module Factory
4
+ class Field
5
+ # There are three ways to add field.
6
+ # *<tt>first</tt> - Pass name and type
7
+ # Field.add(dbi,"name","type")
8
+ # *<tt>second</tt> - Pass it through hash
9
+ # Field.add(dbi,:name => "name", :type => "type")
10
+ # *<tt>third</tt> - Pass dbi_field
11
+ # Field.add(dbi,:dbi_field => dbi.fields.first)
12
+ def self.add(dbi,*args,&block)
13
+
14
+ options = args ? args.extract_options! : {}
15
+ dbi_field = options[:dbi_field]
16
+ name = args[0] || options[:name] || (dbi_field ? dbi_field.name : nil)
17
+ dbi_field ||= dbi.field_by_name(name)
18
+ dbi_field ||= dbi.field_by_association(name)
19
+ association ||= detect_association(dbi,name)
20
+
21
+ type = args[1] || options[:type] ||
22
+ (association ? :array : nil ) ||
23
+ (dbi_field ? dbi_field.type : nil) ||
24
+ :string
25
+ options[:dbi_field] = dbi_field
26
+ if !name || !type
27
+ raise Lolita::FieldTypeError, "type not defined. Set is as second argument or as :dbi_field where value is Adapter::[ORM]::Field object."
28
+ else
29
+
30
+ field_class(type).new(dbi,name,type,options,&block)
31
+ end
32
+
33
+ end
34
+
35
+ def self.detect_association(dbi,name)
36
+ dbi.associations[name.to_sym]
37
+ end
38
+
39
+ def self.field_class(name)
40
+ ("Lolita::Configuration::Field::"+name.to_s.camelize).constantize
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module Lolita
2
+ module Configuration
3
+ module Factory
4
+ class Tab
5
+
6
+ def self.add(dbi,*args, &block)
7
+ type = args && args[0].is_a?(Symbol) ? args[0] : :default
8
+ field_class(type).new(dbi,*args,&block)
9
+ end
10
+
11
+ def self.field_class(name)
12
+ ("Lolita::Configuration::Tab::"+name.to_s.camelize).constantize
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -28,47 +28,25 @@ module Lolita
28
28
  class Base
29
29
  include Lolita::Builder
30
30
 
31
- @@default_type="string"
32
- lolita_accessor :name,:title,:field_set, :nested_form,:nested_for,:options, :html_options,:record,:association
31
+ @@default_type = :string
32
+ lolita_accessor :name,:title,:field_set, :nested_form,:nested_for,:options, :html_options
33
33
  attr_reader :dbi,:nested_in
34
+ attr_accessor :dbi_field
34
35
 
35
- def initialize dbi, *args, &block
36
+ def initialize dbi,name,*args, &block
36
37
  @dbi=dbi
37
- before_init(*args)
38
- begin
39
- self.set_attributes(*args)
40
- if block_given?
41
- self.instance_eval(&block)
42
- process_type unless @type
43
- end
44
- set_default_values
45
- validate
46
- rescue Exception=>e
47
- unless Lolita::Configuration::Field.temp_object?
48
- raise e
49
- end
50
- end
51
- end
52
-
53
- def value value=nil, &block
54
- self.send(:value=,value,&block) if value || block_given?
55
- unless @value
56
- self.record_value
57
- else
58
- if @value.is_a?(Proc)
59
- @value.call(self)
60
- else
61
- @value
62
- end
63
- end
64
- end
38
+ self.name = name
39
+ options = args ? args.extract_options! : {}
40
+ type = args[0]
41
+
42
+ self.type = type || @@default_type
65
43
 
66
- def value=(value=nil,&block)
44
+ self.set_attributes(options)
67
45
  if block_given?
68
- @value=block
69
- else
70
- @value=value
46
+ self.instance_eval(&block)
71
47
  end
48
+ set_default_values
49
+ validate
72
50
  end
73
51
 
74
52
  def title(value=nil)
@@ -87,18 +65,16 @@ module Lolita
87
65
  end
88
66
 
89
67
  def name=(value)
90
- @name=value ? value.to_sym : nil
91
- end
92
-
93
- def type_name
94
- self.type.to_s.downcase
68
+ @name= value ? value.to_sym : nil
95
69
  end
96
70
 
97
71
  def nested_in=(dbi)
98
72
  unless self.dbi.associations_class_names.include?(dbi.klass.to_s)
99
73
  raise Lolita::ReferenceError, "There is no association between #{self.dbi.klass} and #{dbi.klass}"
100
74
  end
101
- raise ArgumentError, "Field can be nested only in Lolita::DBI::Base object." unless dbi.is_a?(Lolita::DBI::Base)
75
+ if !dbi.is_a?(Lolita::DBI::Base) && !dbi.class.to_s.match(/Lolita::Adapter/)
76
+ raise ArgumentError, "Field can be nested only in Lolita::DBI::Base object."
77
+ end
102
78
  @nested_in=dbi
103
79
  end
104
80
 
@@ -107,29 +83,26 @@ module Lolita
107
83
  end
108
84
 
109
85
  def nested_in?(dbi_or_class)
110
- if dbi_or_class.is_a?(Lolita::DBI::Base)
86
+ if dbi_or_class.respond_to?(:klass)
111
87
  self.nested_in && self.nested_in.klass==dbi_or_class.klass
112
88
  else
113
89
  self.nested_in && self.nested_in.klass==dbi_or_class
114
90
  end
115
91
  end
116
92
 
117
-
118
- def set_attributes(*args)
119
- @given_attributes.each{|attr,value|
120
- if (attr.to_sym==:type && !@type) || attr.to_sym!=:type
93
+ def set_attributes(attributes)
94
+ excluded_keys = [:name,:type]
95
+ attributes.each{|attr,value|
96
+ unless excluded_keys.include?(attr.to_sym)
121
97
  self.send(:"#{attr}=",value)
122
98
  end
123
99
  }
124
100
  end
125
101
 
126
- # TODO is this useable
127
- def record_value #TODO test
128
- if self.record
129
- self.record.send(self.name.to_sym)
130
- else
131
- nil
132
- end
102
+ def find_dbi_field
103
+ @dbi_field ||= self.dbi.fields.detect{|field|
104
+ field.name.to_s == @name.to_s || (field.association && field.association.name.to_s == @name.to_s)
105
+ }
133
106
  end
134
107
 
135
108
  private
@@ -141,77 +114,19 @@ module Lolita
141
114
  def set_default_values
142
115
  self.options||={}
143
116
  self.html_options ||= {}
144
- end
145
-
146
- def before_init *args
147
- extract_args *args
148
- set_name
149
- if @name
150
- process_type
151
- end
152
- end
153
-
154
- def process_type
155
- set_association
156
- set_type_from_args
157
- set_type
158
- end
159
-
160
- def extract_args *args
161
- if args
162
- @given_args=args
163
- @given_attributes=@given_args.extract_options!
117
+ @html_options[:class] = if @html_options[:class]
118
+ "#{@html_options[:class]} #{self.type}"
164
119
  else
165
- @given_args=[]
166
- @given_attributes={}
120
+ self.type.to_s
167
121
  end
168
122
  end
169
123
 
170
- def set_name
171
- if @given_args.first
172
- self.name=@given_args.first
173
- else
174
- self.name=@given_attributes[:name]
175
- end
176
- end
177
-
178
- def set_type_from_args
179
- self.type=@given_args[1] if @given_args[1]
180
- end
181
-
182
- def set_type
183
- if !@type
184
- if @association
185
- self.type="array"
186
- elsif dbi_field=self.dbi.fields.detect{|f| f[:name].to_s==@name.to_s}
187
- self.type=dbi_field[:type]
188
- self.options=dbi_field[:options]
189
- end
190
- end
191
- if @type.nil? || @type.to_s.downcase=="object"
192
- self.type=@@default_type
193
- end
194
- end
195
-
196
- # Need here because this don't know how to recognize association.
197
- # TODO maybe need move to adapter, and it is converted there
198
- def set_association #TODO test
199
- assoc_name=@name.to_s.gsub(/_id$/,"")
200
- @association||=@dbi.reflect_on_association(assoc_name.to_sym) ||
201
- @dbi.reflect_on_association(assoc_name.pluralize.to_sym)
202
- end
203
-
204
124
  def validate
205
125
  unless self.name
206
126
  raise Lolita::FieldNameError, "Field must have name."
207
127
  end
208
- #FIXME need this validation
209
- # if !@value && !@dbi.klass.instance_methods.include?(self.name.to_s)
210
- # raise Lolita::FieldNameError, "#{@dbi.klass} must respond to #{self.name} method."
211
- # end
212
128
  end
213
-
214
129
  end
215
130
  end
216
131
  end
217
- end
132
+ end